mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-08 20:41:38 -07:00
Compare commits
1724 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74458ab096 | |||
| c39b1a31db | |||
| 635c7fa153 | |||
| b7ac0a9e8d | |||
| 3f3ae4b2b6 | |||
| c2423dc07f | |||
| 1296630160 | |||
| 63eec25044 | |||
| 7a9b0731cf | |||
| d45661c405 | |||
| 002bec256a | |||
| 000861cba8 | |||
| 36473b2774 | |||
| 4188f50105 | |||
| 3e3b9ae2df | |||
| e89f0de232 | |||
| 4858e16a11 | |||
| 902a6db0e1 | |||
| 19ae6122c7 | |||
| b82b91ea08 | |||
| 636f0d7063 | |||
| ed73441a4c | |||
| 4c2be6cd49 | |||
| f3f51bd643 | |||
| 4c5672119a | |||
| 8482f943ea | |||
| 15aaf7dfa0 | |||
| 768abf83f6 | |||
| ca76d53452 | |||
| b0904d6598 | |||
| b0a09f7b9e | |||
| eb4891bcc8 | |||
| 803fd8f037 | |||
| 67bdb5b1a3 | |||
| acc635b535 | |||
| 4e8ce87792 | |||
| 2c8daa25dc | |||
| 054ee0a8b5 | |||
| d0cadaf1a6 | |||
| 317db2758a | |||
| 25102d4792 | |||
| d39f1c461e | |||
| 7a6fc3a93b | |||
| 83c002c197 | |||
| fc47b5dee0 | |||
| 6c2e0b09ba | |||
| 3d4698debe | |||
| 4a25cfb27c | |||
| 294bd6a446 | |||
| d0109db23b | |||
| ee3ee66aae | |||
| f74e281efa | |||
| c0cd02883f | |||
| d9adb0fd6b | |||
| 6363013dd8 | |||
| 934131abf8 | |||
| 4e5337412a | |||
| 00f2e911a7 | |||
| c82d7d3d87 | |||
| ecfea027a0 | |||
| 96be494730 | |||
| 12c8db927b | |||
| 027ea587fc | |||
| 026900c7f0 | |||
| ffa87f55c4 | |||
| c9eed04b51 | |||
| b50b6b9f33 | |||
| 8fd5bef0bd | |||
| d6b49994a2 | |||
| 776927709b | |||
| 96e033b22c | |||
| 3469178dc1 | |||
| af1b3b6368 | |||
| d56789e5a7 | |||
| aeacf3a9d8 | |||
| 4ba486baa2 | |||
| f1ffd90294 | |||
| 777aa8b118 | |||
| cb9e16f4df | |||
| 2908923db9 | |||
| 8c1dfabb6b | |||
| 7fe36de069 | |||
| 27d556735a | |||
| b70d211f21 | |||
| b3e3b6c656 | |||
| 1734286252 | |||
| c8c076f970 | |||
| e40b3ad338 | |||
| afec321db2 | |||
| 6e9f9e6f3c | |||
| f504b200a9 | |||
| 82e840a0ca | |||
| 82765ca96e | |||
| 5387ec5f29 | |||
| f2908cbc5a | |||
| 5337b0b471 | |||
| e51afc3509 | |||
| 2c004dbcc9 | |||
| e128ed7d26 | |||
| 9064ebfe97 | |||
| 4f7bbe0e4a | |||
| 208f168564 | |||
| 737bccbd5e | |||
| f5431a046d | |||
| 5a9422b6bc | |||
| d30198c99a | |||
| 0c8d59dd20 | |||
| a460d140fe | |||
| 881d18ee88 | |||
| d73a4aa34b | |||
| 5c298c1501 | |||
| a83ca2120e | |||
| 81799f7f78 | |||
| 7973f7e750 | |||
| 3dc62a67e0 | |||
| 081e36c909 | |||
| 3a1d364f59 | |||
| e50648279d | |||
| 929af320da | |||
| 8e7c7eeeba | |||
| b739044e69 | |||
| 9e0107c9fc | |||
| 107e016508 | |||
| 22d16c20f8 | |||
| 697c839c84 | |||
| de8bd88d2a | |||
| 595efba747 | |||
| c041d15569 | |||
| 57b20e634b | |||
| e285796fc1 | |||
| a19494d3a7 | |||
| d2a362fd52 | |||
| 0f3562ef02 | |||
| 03f683f9e7 | |||
| cecadce86d | |||
| a7c3906003 | |||
| 70dc0c15fd | |||
| 9eeed9d5bd | |||
| a054c2934e | |||
| 38102f14c1 | |||
| 0997df4fcf | |||
| a5a56e061c | |||
| 8b007ad55a | |||
| 57dd5ec4db | |||
| 5b621d5be1 | |||
| 7aee762f3a | |||
| 4ee50c5a35 | |||
| 28f440dd9e | |||
| 43b78e51a4 | |||
| 84f9fb706b | |||
| 812823cad8 | |||
| 0655260378 | |||
| cfc3723879 | |||
| 4c3281b3f2 | |||
| ff94c605e0 | |||
| cb0a59bb2c | |||
| 076700bd22 | |||
| bcccc8338f | |||
| 425dec8bb8 | |||
| 838554460b | |||
| 659c3c528d | |||
| 60aeab3c38 | |||
| 5e3cf45df3 | |||
| 4633591918 | |||
| 0e6a8b7c72 | |||
| 147848ca20 | |||
| cde002c579 | |||
| f23d93ba89 | |||
| c97a8418dc | |||
| 4aca9372a6 | |||
| 4912ecc3ea | |||
| c1c8ceafc2 | |||
| 9c0a3b6c60 | |||
| 7b539e3025 | |||
| b2b0043875 | |||
| 53e0d182af | |||
| a6fa41e290 | |||
| edba99d636 | |||
| 35674959f2 | |||
| dc8b7a0eb8 | |||
| 8d1f46d837 | |||
| a2117d23b2 | |||
| a58e4d0359 | |||
| 576914aee1 | |||
| 8171f8209a | |||
| 64ff05303c | |||
| 6caab6225d | |||
| 326411498a | |||
| d50fcf0020 | |||
| d354d36a3b | |||
| 483a72ac61 | |||
| dbec4b0d0e | |||
| 4cb489b9e4 | |||
| 28ec50d567 | |||
| 73beed0477 | |||
| e0ecdd4b24 | |||
| 0cb1a578d0 | |||
| 5168cf03a9 | |||
| b886ae6515 | |||
| 277a973b98 | |||
| 0ec4d97bfd | |||
| e6236e5c3e | |||
| e201280844 | |||
| 8e50a6c61b | |||
| 7e6f5f89d0 | |||
| 97acc57649 | |||
| 83c8c48ed7 | |||
| 0815b4d59f | |||
| a0135080b3 | |||
| f45e8e5d47 | |||
| 98ba4beede | |||
| a9304f2fef | |||
| a0697ab057 | |||
| 2e895c72d3 | |||
| 674ebe395f | |||
| 96eecaab54 | |||
| b1ae5bc9fe | |||
| 7258588ed5 | |||
| d913155972 | |||
| 9746e25784 | |||
| d26cfd2141 | |||
| 21f2c06f4b | |||
| 727a25f41f | |||
| 3f27cb2309 | |||
| f213622982 | |||
| 4aad835a66 | |||
| 4af8a64580 | |||
| c9c3611b1d | |||
| 220dfd7440 | |||
| bce8819ed5 | |||
| 5f2b220a85 | |||
| f174c805a9 | |||
| 25869b7504 | |||
| ecd81e8a53 | |||
| d7f9f7f170 | |||
| 08f5259d77 | |||
| a9f744cb64 | |||
| b02e42c6dc | |||
| cb0273b5d7 | |||
| 8dbf45a65a | |||
| 9f64de9568 | |||
| 0ebe9ba487 | |||
| efe00e1aa6 | |||
| 2bdbce55f9 | |||
| 9614ca92f0 | |||
| d30e59f539 | |||
| a3afe617c2 | |||
| 69daac583e | |||
| b28d4b753b | |||
| e6ab4f4856 | |||
| c8ab1b7ee1 | |||
| 9f10487678 | |||
| 2542983d70 | |||
| d492fb3501 | |||
| 1829aa1638 | |||
| 4cb4173ced | |||
| 00e704b216 | |||
| 227ee0f705 | |||
| 17f47a7ab0 | |||
| 4e8bc0786d | |||
| 3d3ccf061f | |||
| 3a8adc6721 | |||
| e1748a5dd1 | |||
| 59b4c889d3 | |||
| b6408d1b3f | |||
| 3db3047f47 | |||
| 7420fbd95b | |||
| 7c990b3833 | |||
| 9c059f1a12 | |||
| fb167d1d0a | |||
| 0992239d86 | |||
| 9eb3da0474 | |||
| e91f8feedf | |||
| 22a0c3fce1 | |||
| 6c7e5748a8 | |||
| 0b0c6da8b0 | |||
| 78826071c0 | |||
| e61b73d7ad | |||
| f886632bf1 | |||
| eafa5098aa | |||
| 0571b80d37 | |||
| 80c10644dd | |||
| 041625381c | |||
| 48f56d728b | |||
| 872d391cfb | |||
| 3e6ec65dd9 | |||
| 157c87b2a2 | |||
| d3081bd889 | |||
| 2ae5bf4395 | |||
| f28547cae1 | |||
| 5332705e31 | |||
| bfb082cda4 | |||
| 37d04198ab | |||
| ae9d540c1c | |||
| c90b7c38f1 | |||
| 9e376fbda7 | |||
| 00739bf06d | |||
| e8148055ad | |||
| dd0a20ab45 | |||
| babbc304b8 | |||
| a8b44f33bd | |||
| bd48561688 | |||
| 23842a8950 | |||
| 1676c643df | |||
| e2bfb024de | |||
| 4d06a54c0c | |||
| 0a8e6169d7 | |||
| 04ae87eaef | |||
| b313d09c2c | |||
| c0d2359a91 | |||
| 51a2f09032 | |||
| f60e8031f2 | |||
| ea42613fec | |||
| b89bb87759 | |||
| 2cbb3d5a24 | |||
| 9e288b7ce8 | |||
| 776b48c10d | |||
| 199dae6cd5 | |||
| e58f45bef7 | |||
| abe122ecb7 | |||
| f8744d87b0 | |||
| 3e7f6b8751 | |||
| 6ffe814ca7 | |||
| eec9be71f6 | |||
| 888913c739 | |||
| 33d96fd28a | |||
| f1e8738af2 | |||
| 9c52a11b1b | |||
| d89c4606bd | |||
| c6903fbcd5 | |||
| 13c8149046 | |||
| 665db0f778 | |||
| 173286de65 | |||
| f2ecda8fec | |||
| 6f1222e9bf | |||
| 84a424f21e | |||
| 9b7710488b | |||
| 9f413862e9 | |||
| b8802d7df7 | |||
| b13dad02a4 | |||
| f045f8d805 | |||
| 30b7c8ad66 | |||
| 89222a0ab2 | |||
| 21e637d2b3 | |||
| 6c196931d2 | |||
| d7195b0798 | |||
| b40998de9e | |||
| 8c0c327df9 | |||
| 50cbb8a1fc | |||
| ff9d058392 | |||
| 1acc8f438b | |||
| c53426fcb4 | |||
| 5187db525f | |||
| a8bd340267 | |||
| ca1f419dc2 | |||
| fae60a6b88 | |||
| 108558ddfc | |||
| 65b8cfae82 | |||
| 4055c31cf0 | |||
| e88af4e458 | |||
| 79eb7b52d9 | |||
| 83b2bf44c4 | |||
| 670f18ad1b | |||
| 9a81716936 | |||
| f013499eea | |||
| d04f732e68 | |||
| 35fd8e7f68 | |||
| 38ff2a3ed9 | |||
| bd502d16bc | |||
| a11e17fbc3 | |||
| 8b3b659433 | |||
| f33228fd6e | |||
| df5b693de8 | |||
| ab98108441 | |||
| 6f80174f84 | |||
| 0ebe81fce2 | |||
| c75dd14308 | |||
| c166b6a21d | |||
| 6ed5cbee12 | |||
| 5b200ccdf8 | |||
| cf0f0c4b31 | |||
| 1399ecb41c | |||
| 339d6cfd41 | |||
| 7bded4f189 | |||
| c7269b9ef0 | |||
| 85688015aa | |||
| 3c6cc575c6 | |||
| 0564cb6483 | |||
| 4be92c7eb8 | |||
| 88e9eb7d0c | |||
| d19fc54c3d | |||
| 5d4291d9fa | |||
| b70cd03e9e | |||
| e91e5e1fe9 | |||
| ae57a49915 | |||
| bfcb527b42 | |||
| a343fb171d | |||
| fa2296a124 | |||
| a996cfc536 | |||
| c1d55b9296 | |||
| 5c18cca1ca | |||
| 78e6cd0c60 | |||
| 176954a6d8 | |||
| ad6b3bd95f | |||
| 762895bc45 | |||
| 592e9afa5f | |||
| a2e0373934 | |||
| fb49841b1d | |||
| 01ea0d6f1e | |||
| bb7f291f5f | |||
| 174fa9b490 | |||
| dda2ed290a | |||
| ee9908b09e | |||
| 66de1856e3 | |||
| ba5f7c4e2a | |||
| 487bd3d942 | |||
| 4fac7a8f27 | |||
| 25dae06b6a | |||
| a1f15c2c69 | |||
| 516f6647b4 | |||
| a7840d50e2 | |||
| cb10af08cb | |||
| 4e49d24df9 | |||
| 68222cb8ab | |||
| 912d29af83 | |||
| f3868ac932 | |||
| 5b42dd7707 | |||
| 51707032d1 | |||
| a0babefe55 | |||
| f3aefbc443 | |||
| a6c779b50e | |||
| 9fa41a97b9 | |||
| cef022539e | |||
| f6dfa33697 | |||
| bc3bf939e0 | |||
| f5e5eac3b9 | |||
| d50786bd30 | |||
| 0ccbea17aa | |||
| 136d50a745 | |||
| babfba5e8f | |||
| 846f8377b2 | |||
| 77d4409549 | |||
| 7f3540b7f5 | |||
| 3ad2cde833 | |||
| 910799cc5f | |||
| 6c0192083e | |||
| c60d7842cd | |||
| d7eaf0f87b | |||
| bb4329711c | |||
| 618d3bf62f | |||
| cf8a4b9812 | |||
| 4db533ff71 | |||
| f28e3276e7 | |||
| 026540040d | |||
| 8518d3b232 | |||
| 1c1f5e2231 | |||
| bdedfb1071 | |||
| 92ed9e0b94 | |||
| 5c10b35df7 | |||
| 0668811397 | |||
| 6bb6344208 | |||
| 2f7bd154a2 | |||
| 20c5033b38 | |||
| 20fe6d102a | |||
| 4e30a64d9f | |||
| c48ef7d70b | |||
| e079a7009d | |||
| f383bf3136 | |||
| 609ddf28b7 | |||
| 34f1bda57c | |||
| f137b927b6 | |||
| 2185dada56 | |||
| 0b08080119 | |||
| 432b2b19e9 | |||
| 952f294bce | |||
| c23274adb0 | |||
| 833f9dd037 | |||
| 1ff8b97dae | |||
| 70451f9335 | |||
| 1f438d4e6c | |||
| 421d45a7a7 | |||
| 20e7b5c88a | |||
| 7092273a8f | |||
| d0e8a735ba | |||
| 208226dba2 | |||
| f308f37ba1 | |||
| c2610cb75e | |||
| 59e9df2609 | |||
| 66b5a35ec3 | |||
| f3f6c12a7c | |||
| e331b0647e | |||
| 35502816c7 | |||
| 7ec0236fbf | |||
| 0fd43c1a0b | |||
| 06337129d8 | |||
| 337780497d | |||
| 10deb2e88b | |||
| b95ca80f85 | |||
| 83d880a94a | |||
| cde6a2f7a5 | |||
| c2f5cbdeb4 | |||
| 8e57511ffa | |||
| 12d19d21c4 | |||
| 7002c94a63 | |||
| 57e69ea392 | |||
| 09f936b04d | |||
| 140c00aa0c | |||
| 808ea30b48 | |||
| 63d6c08d90 | |||
| 10e4de3c01 | |||
| 8ac12886ed | |||
| 63cc8a80a0 | |||
| 1549d01bf7 | |||
| b168bf9460 | |||
| 0203bb657e | |||
| 53f0c6ef1a | |||
| 4c4480104d | |||
| 5c72974167 | |||
| f21e9ee712 | |||
| 81dd727f75 | |||
| 3b54015e80 | |||
| b032d5af87 | |||
| 209a155608 | |||
| d8e77cd738 | |||
| 95d4ce4aa3 | |||
| 39393cca92 | |||
| acadbe050c | |||
| 8fcf2f5dca | |||
| 831a86599e | |||
| 233b32fd3e | |||
| 3c5124ce68 | |||
| a8d78660ee | |||
| cc1df9591f | |||
| 54a326f046 | |||
| 3d9d85121d | |||
| a31d23a32a | |||
| 084f431aa5 | |||
| 7002f0a7d7 | |||
| 3ec70c5517 | |||
| d9f293b281 | |||
| 8c1499dbc2 | |||
| 7d2eedee73 | |||
| eba35a8f7d | |||
| e967f2ca2c | |||
| 438713af20 | |||
| 568869077e | |||
| f25a3f2a7d | |||
| 5609221831 | |||
| f3432e6bb5 | |||
| 43b350c590 | |||
| c2c66aad60 | |||
| d7681d5b06 | |||
| c902615192 | |||
| 2895830ce6 | |||
| 1eef9552b4 | |||
| 577fa2d29b | |||
| 72fcf16a39 | |||
| b9d523e0b2 | |||
| f3d225ca4f | |||
| d84d2f85e8 | |||
| 10f1d8c604 | |||
| 184d1c57b1 | |||
| dfbe68bcfe | |||
| 3049e07f72 | |||
| da54d0ec8c | |||
| b57edb89eb | |||
| e43eccbb91 | |||
| e48f41165c | |||
| 9eb4cbcbd2 | |||
| 2612f241c9 | |||
| 0f1153fae2 | |||
| b84561f2b8 | |||
| f7e78e2671 | |||
| d10a2bc5d5 | |||
| 94fda3d48d | |||
| 5cf4f565d6 | |||
| c20b5cbd10 | |||
| 115612620f | |||
| a5bf3b0bc5 | |||
| 5c647e2f61 | |||
| 06884da42b | |||
| 6e7179d8f3 | |||
| e85f1dd9fb | |||
| 9ac94e621b | |||
| db8d119cad | |||
| 836c325021 | |||
| 3bb31093fa | |||
| 214b43974d | |||
| 55556aea77 | |||
| 223897d224 | |||
| 542e45de26 | |||
| 1fa9488a4d | |||
| b1196bd659 | |||
| 57167be2a6 | |||
| 846930a07f | |||
| 0cc67ff5e3 | |||
| a86574da84 | |||
| 5a6836ab99 | |||
| 43432f92ec | |||
| d1499f3f78 | |||
| fff23e2bbb | |||
| 33895b6d92 | |||
| e10105a780 | |||
| 5451c9672d | |||
| 4eba2bb8d9 | |||
| 2a58bceb56 | |||
| fdcf08410c | |||
| 5142955f00 | |||
| 500150b12a | |||
| 50ddd8dd26 | |||
| 6c6de2a07d | |||
| 01912b6ba5 | |||
| be2c7b5c9b | |||
| ed60ed3bae | |||
| 23cb96de02 | |||
| a2c771876e | |||
| b5b329378f | |||
| f7b18cd86e | |||
| d74e4b427d | |||
| 22dc020647 | |||
| e8485ee7e7 | |||
| c516fb947f | |||
| 3aa0a733f3 | |||
| 4e080057fb | |||
| 9c1f270bd5 | |||
| e46d87b221 | |||
| 5bc866e420 | |||
| 5af7004f44 | |||
| 01e8e682c0 | |||
| 2ef6544ca2 | |||
| 9921ac01cc | |||
| 7057f5fc11 | |||
| f17a9dd5e7 | |||
| ec3394b8da | |||
| 0cca42a1f4 | |||
| 85edcf9cc2 | |||
| 3b842ffe29 | |||
| 6c0e2e2a53 | |||
| 42371f7aea | |||
| 286f782e5e | |||
| 58fc305b11 | |||
| 7e0c359f99 | |||
| f50399e394 | |||
| 7bc21c6691 | |||
| dd56c85e55 | |||
| 9e2a847ebc | |||
| daef39a206 | |||
| 5d496cdcda | |||
| f27f595549 | |||
| 536e0a8c29 | |||
| bc18310107 | |||
| 3fdb3dd767 | |||
| d224679619 | |||
| 2dd181e663 | |||
| f002857edc | |||
| 97739da85a | |||
| 6c14586fff | |||
| 0c45a46aab | |||
| d1fc9d3073 | |||
| 2fb351bf04 | |||
| dc832ad49f | |||
| eef44b11f3 | |||
| bb4f108487 | |||
| ccb38c3dc6 | |||
| cc81057d21 | |||
| 8b4b81fdeb | |||
| 4cb46f5631 | |||
| f4ad4c7aa6 | |||
| 37dda30c49 | |||
| 8fb718245a | |||
| a4cb6f96ea | |||
| 56e3b7cb7d | |||
| ae1f5d2181 | |||
| b4df272eb5 | |||
| dca2fbccff | |||
| d48d3bfa87 | |||
| 8559790bd8 | |||
| 37c6279031 | |||
| 0d4e710b96 | |||
| 205aa10b88 | |||
| 6f1cc3946b | |||
| 253ecd55a0 | |||
| c9e31dc90d | |||
| 3d06322d4a | |||
| 85e6efdf16 | |||
| 6b89ff43ea | |||
| 4cdc55af91 | |||
| 4b289f904c | |||
| 53c70da0b8 | |||
| 6f20b5bb59 | |||
| 96ab17ecfc | |||
| 18bde22b26 | |||
| e61aad925b | |||
| 5d190b15d7 | |||
| fe442d7c0c | |||
| 97d1a67871 | |||
| bac96cf2ad | |||
| 7e0cc0af25 | |||
| 1d29d9be25 | |||
| 0e91e63043 | |||
| 0cf37bde8b | |||
| 173799527a | |||
| 5931e2383b | |||
| e4743b15b1 | |||
| 9f95d6fa65 | |||
| 982a1aebb3 | |||
| cec049b7d3 | |||
| dc323cfa1d | |||
| 0afa226a93 | |||
| 1146604344 | |||
| 89c2e1a5fa | |||
| 971d498e79 | |||
| 6e7a50c02f | |||
| 6aaab4988e | |||
| d9b0c05acf | |||
| 47f637d23b | |||
| 59f55a2119 | |||
| 8bac82320f | |||
| 14bf20320a | |||
| b99940f33a | |||
| 81495068b9 | |||
| 6985181961 | |||
| 97717d65ef | |||
| 8023c8abc7 | |||
| 2d3f59d9a7 | |||
| be8de4a1ff | |||
| 18ad6c33ef | |||
| 0e27b27b81 | |||
| 10a311092b | |||
| 18463d68d4 | |||
| 74d3bcec05 | |||
| df233aee94 | |||
| 335b724209 | |||
| b2fdb881eb | |||
| 6ade9acc4d | |||
| 2081f8fcd6 | |||
| 964ab4814c | |||
| 7a032cf9f9 | |||
| 694c13fe86 | |||
| 8bd16c32f3 | |||
| be9b935953 | |||
| 9e69452327 | |||
| 234d529867 | |||
| dd8b71e353 | |||
| d24bebdb9e | |||
| 41a18f078d | |||
| 3978e7e1ca | |||
| b758c696f2 | |||
| d6a8216ce4 | |||
| 2720f64c06 | |||
| de2ebdd5cc | |||
| 4e39629a9a | |||
| 78a8da5fea | |||
| d5886c1572 | |||
| 7cc759a855 | |||
| dd6337224f | |||
| d2bac0c35e | |||
| 8c7f3fd1e6 | |||
| ae3deea153 | |||
| 40bea95fb0 | |||
| 0ad448f1c7 | |||
| 4911df9f99 | |||
| a223340c44 | |||
| 9c9c2b483c | |||
| 819345caa6 | |||
| 11ceb3973d | |||
| 36263399a0 | |||
| ff0f0c447f | |||
| aa681932a9 | |||
| 09e1c0fa27 | |||
| 957ef8e8fe | |||
| 2e11a8da5b | |||
| e9cfcf9ecc | |||
| 789ab99c4d | |||
| 0297db6f2e | |||
| 9ce64916e6 | |||
| 1289c96e2c | |||
| ba23bfb7b9 | |||
| 2fae6eda23 | |||
| e53ba3b116 | |||
| 1ed84a064b | |||
| 79019c7a09 | |||
| a1002e6960 | |||
| 62139cb5a4 | |||
| 127b0ba65e | |||
| 80878264b6 | |||
| 9fcba99ca2 | |||
| 03c9212600 | |||
| 5650087aa3 | |||
| 67689ecb21 | |||
| cd13dedb36 | |||
| 10cd294cf2 | |||
| d6cfb60506 | |||
| df0df73540 | |||
| 33f1418dec | |||
| 305510bea0 | |||
| beb698f31d | |||
| 6df21d6a9f | |||
| c5982e52d5 | |||
| bd73b2845b | |||
| da0f722aad | |||
| 904f0407f8 | |||
| fbbb0d7610 | |||
| 3a9b0a22e7 | |||
| c4e0d1efa1 | |||
| 9349dfba8f | |||
| 9692496989 | |||
| 5bc8164274 | |||
| a6cef2e50e | |||
| d262eda91c | |||
| 40f0f5ad8d | |||
| 1c03e68057 | |||
| f1c1cfb6d2 | |||
| ba5e33bc35 | |||
| 80df9fbc65 | |||
| b68ab0dd6d | |||
| 9cf7a31068 | |||
| 5e11ad2e1e | |||
| 07d1a42768 | |||
| ec8221cb5d | |||
| a5342a0126 | |||
| c81fd2e5dd | |||
| 3bd7122959 | |||
| 530401e5ee | |||
| a412d34574 | |||
| ee67a0b9a1 | |||
| ca6a1db757 | |||
| 1fb76ad768 | |||
| e01662c139 | |||
| 63331ef731 | |||
| a40a53b104 | |||
| 9f8d90f466 | |||
| 3d2856db31 | |||
| f4723aea4c | |||
| 76d48b38d3 | |||
| 3cab2592c3 | |||
| 5422a3b17e | |||
| b44b6e7e50 | |||
| 849efff070 | |||
| b022167df1 | |||
| ac9a358c65 | |||
| e799476f90 | |||
| b4f8efcbe6 | |||
| f026753692 | |||
| 71b1cce517 | |||
| d8f0da164b | |||
| 591732f347 | |||
| eee97f7f62 | |||
| 3dd9da1b66 | |||
| e8c0be23f2 | |||
| a30b9b17b3 | |||
| 29b2c04766 | |||
| d869ba7bcd | |||
| 581255bf23 | |||
| b51358a01c | |||
| 323e7a2d02 | |||
| 7654afc2db | |||
| ded8342f3f | |||
| 240fb9b953 | |||
| 4997a43763 | |||
| aa4eb35671 | |||
| d99ba9c073 | |||
| fdd24f787f | |||
| b6abd691f4 | |||
| 8d370fabdd | |||
| df4a0c62ad | |||
| e3e3309a9b | |||
| 7428e52264 | |||
| 20b70c3b7b | |||
| 4247ba67ed | |||
| e738e93da0 | |||
| b78f3a8069 | |||
| 939973acd7 | |||
| ed4cb72b19 | |||
| 70cbffd58b | |||
| 6d0ba8d189 | |||
| b6f3fa6ee1 | |||
| 91037766d2 | |||
| 8bf73950fa | |||
| 4f4793817c | |||
| 0a0440a6e8 | |||
| b9dc81d808 | |||
| 8e7ddccf00 | |||
| a5773f1657 | |||
| 44316401c9 | |||
| b05fbaacda | |||
| 1b4d5b73ab | |||
| d3fbf36df7 | |||
| de819cff94 | |||
| cfae39c29d | |||
| 989641a616 | |||
| fc3f62e3ed | |||
| 6b7c04e046 | |||
| cfeb16f917 | |||
| 9a2d9002e6 | |||
| ea0b02d9b9 | |||
| 0d621511e5 | |||
| e53c858855 | |||
| 8a9f7fc684 | |||
| 51db46551e | |||
| 600b79276a | |||
| a040be957f | |||
| f6fa553572 | |||
| 8310436350 | |||
| f92ffe60e7 | |||
| de72754d7a | |||
| bf712e9355 | |||
| ab9457346d | |||
| 15b440c4f1 | |||
| 1a2c36e482 | |||
| 56737c1431 | |||
| 9ae566adcc | |||
| f2f1330238 | |||
| c4a7739d13 | |||
| 8a8b5c753f | |||
| ad90f416a5 | |||
| 698fcb7813 | |||
| aadb4db211 | |||
| 426a6a9528 | |||
| 50b9c48609 | |||
| 767ed21bfe | |||
| bb9165edd2 | |||
| ad0a413b40 | |||
| 7f6c6945ae | |||
| ca549939f3 | |||
| cdb003bf23 | |||
| a4d2ff05a9 | |||
| 48012ec73c | |||
| e7dc00b758 | |||
| ef1fbbbce6 | |||
| 2a59aebe5b | |||
| 59025b75ba | |||
| 2289b7a33d | |||
| 79ec172797 | |||
| 2e6ad2a711 | |||
| 6be05f315d | |||
| b5aa50aaa4 | |||
| ab91fa6ad5 | |||
| 376327c87b | |||
| f8f91e52e0 | |||
| f4daf46ff4 | |||
| e80bee6867 | |||
| d10d54710c | |||
| 1ec997461d | |||
| ec5fc10988 | |||
| a232c0888c | |||
| cb5a6b531a | |||
| c930a3b4c8 | |||
| 4c14e92952 | |||
| 850d4a1e1b | |||
| 88de3a1c06 | |||
| dc012ed6dd | |||
| c21c993646 | |||
| c3a292a8c7 | |||
| 4044a577cc | |||
| 581d53b96b | |||
| 2bc89260f1 | |||
| c78b83f142 | |||
| e28525e28c | |||
| 73f9d12d47 | |||
| b21cf05d44 | |||
| 107bede9fd | |||
| 75cbb09744 | |||
| 76cf667a29 | |||
| 78ee97ec74 | |||
| c686133172 | |||
| bfcd7a35bf | |||
| 4484a3433d | |||
| 0c4f905d82 | |||
| 77de7ebde5 | |||
| 2ec3fa93b4 | |||
| 9f2d710c35 | |||
| 22b961ea53 | |||
| 9ea45d35db | |||
| 06e8476efc | |||
| 94dbac9a64 | |||
| 97a183f412 | |||
| b2f5b73532 | |||
| 1eac3482a6 | |||
| 6636376a81 | |||
| ed6bf28004 | |||
| 6bc0c611ab | |||
| ba1930eb01 | |||
| 203382461b | |||
| 6456618891 | |||
| 4eb4ae6305 | |||
| 72ae061769 | |||
| 46161f7e19 | |||
| 0c55596f0f | |||
| 5f3bfa66c5 | |||
| 561b725b0e | |||
| 3a4630e6b4 | |||
| abf0fd7efc | |||
| a632db3618 | |||
| a3c81374be | |||
| 6a3ec5eb36 | |||
| 740ba6ad47 | |||
| df32b5b46c | |||
| 085fa199ea | |||
| 412c9a99d5 | |||
| 6e701ef36d | |||
| 24c48d22bc | |||
| 3cb8bb6672 | |||
| b1c2c0ea7a | |||
| 2c498c132e | |||
| 880d330cca | |||
| a2a503847a | |||
| 58f4d533b7 | |||
| d2ff6f424d | |||
| 92f985abd5 | |||
| 3ce17607c6 | |||
| 76277f83c1 | |||
| 2b7529977e | |||
| f4125d2d88 | |||
| 87e50e5e4d | |||
| 86a1c34c3a | |||
| 3f3cc342b4 | |||
| 3bf820cf99 | |||
| f2b4087d80 | |||
| 3b6d72bb94 | |||
| 9080fa4a9d | |||
| 5616ff9a40 | |||
| 73b81184fa | |||
| f8d3f86d8b | |||
| 2f9a410a45 | |||
| 8661457512 | |||
| 5d7b92d391 | |||
| 1d8bc3e917 | |||
| a2ad16b609 | |||
| a3b1ac3133 | |||
| e7b96cf286 | |||
| 01181517dc | |||
| f702c782f1 | |||
| 7203560b06 | |||
| 1baeb9406f | |||
| 17e36bd5e1 | |||
| b6b3377786 | |||
| 13cb894b30 | |||
| 3f935bea25 | |||
| 3e66eec735 | |||
| 277e0ac124 | |||
| 2ccfaa7d4e | |||
| 4bd5de34ea | |||
| 374e71e9b0 | |||
| 07bb93bb5d | |||
| e252d3bedf | |||
| b9efd09d17 | |||
| 507b718cb3 | |||
| 82f9cbecf8 | |||
| a8ac59a6e7 | |||
| 3d389ee028 | |||
| 10c5825715 | |||
| f89ebce807 | |||
| 64601ac439 | |||
| edce27812f | |||
| 193822b45d | |||
| 43640a8b59 | |||
| 0446d9721b | |||
| bae13b6387 | |||
| e48c0eee74 | |||
| 47e9857eb7 | |||
| 559fcfa291 | |||
| 84cee5d9d5 | |||
| 6d354524e2 | |||
| ae6441182d | |||
| a68f0b2d72 | |||
| fdbbf24271 | |||
| df233f72a9 | |||
| bff5a67f79 | |||
| 4f9df50dc1 | |||
| 34187424b8 | |||
| 50503cb405 | |||
| 5e04ddd653 | |||
| 4f5203e661 | |||
| d9ca4eb4d6 | |||
| 5534c031b3 | |||
| 19dc84e300 | |||
| a932168f50 | |||
| 36c22393a4 | |||
| 6d6e840bc2 | |||
| 4b1822ade8 | |||
| b21e7e4518 | |||
| 1f4e5e919f | |||
| c293e88f2e | |||
| 1d147ba993 | |||
| 6ea9ba16e7 | |||
| 286549693e | |||
| 34727f99e3 | |||
| ffe6d81ecd | |||
| 8605833781 | |||
| 4474144c24 | |||
| ef3f448861 | |||
| a882260db6 | |||
| 633157f4f8 | |||
| 9fa69c3d3b | |||
| 743a461aa9 | |||
| fc0291d745 | |||
| 77eaf8e1e4 | |||
| a7adb2fb6e | |||
| 036900da51 | |||
| ed4c9335db | |||
| ca67cf032c | |||
| f907516cbd | |||
| c12c7d5370 | |||
| f7c8b40ea2 | |||
| 15f9795ab0 | |||
| 8982ae34e3 | |||
| e6d3e893a5 | |||
| e008b5a160 | |||
| 3da8fa9b27 | |||
| 32ba5e7ad2 | |||
| 52df80dccd | |||
| 7f845bb165 | |||
| 0e6de5673b | |||
| 7a7b87181d | |||
| c6dc517004 | |||
| 0b61215f7b | |||
| b91c0ec715 | |||
| bad295cf69 | |||
| d2bc41a2df | |||
| 7dbcaf792d | |||
| 2652c2d7a5 | |||
| a2250a5d49 | |||
| 7f8a9587e0 | |||
| 1306c53fb1 | |||
| 3bd1ac4c82 | |||
| dc8d28c383 | |||
| 7adaa4dc2b | |||
| 6d1a91f5b3 | |||
| 17eebf338c | |||
| c543ecd64c | |||
| 34a9f55f37 | |||
| 9aea990184 | |||
| d5b0632e4f | |||
| db169a4334 | |||
| f5cc8bd7bf | |||
| 005d52cab7 | |||
| d1477bcfa7 | |||
| 3092fb2ff3 | |||
| 5eebdebec8 | |||
| 8e4d6b3e5d | |||
| ea9c2fed57 | |||
| ba412fd87b | |||
| 0278ac85a0 | |||
| ff60b752bd | |||
| 832003dd4b | |||
| 9848e883c7 | |||
| 64705ddd1d | |||
| 2a41814985 | |||
| 26ffec845b | |||
| 52e60526ef | |||
| 76b10b5f5d | |||
| b94a7a87fa | |||
| 2b43387a9d | |||
| e76a5d8e12 | |||
| 6d7217f37a | |||
| 17dab04422 | |||
| 29e660b16f | |||
| 31959b0751 | |||
| 1f19610fd6 | |||
| 8f897de267 | |||
| 2855ff6df3 | |||
| deed20dea6 | |||
| a6c5143993 | |||
| 758d1e2a03 | |||
| ce057ff755 | |||
| ad719e7c3a | |||
| bff3426d25 | |||
| 4315033220 | |||
| 1cd89b2da3 | |||
| 658a605c75 | |||
| 7e8b9862b9 | |||
| 07062324d7 | |||
| 2e8f2e6dbc | |||
| 1abd95094d | |||
| 913d802e33 | |||
| bee475c38a | |||
| b4ca99ead9 | |||
| dfe2c0a600 | |||
| fad851d80c | |||
| 832961d539 | |||
| 499c657ffa | |||
| e51bb4ef12 | |||
| 8c6f39a68d | |||
| 09f5713cf8 | |||
| 26c0c6a525 | |||
| 6d9f84ba03 | |||
| 8af08f2153 | |||
| 2944969ca0 | |||
| bd1b54e0db | |||
| fcab5508be | |||
| 0b05650366 | |||
| 96e36c7c39 | |||
| 16c6dbcbe5 | |||
| 92a78c83d9 | |||
| 6b2302fa8b | |||
| ee28945e09 | |||
| 3dcea60f5b | |||
| f126e05034 | |||
| 68b74eb7c7 | |||
| 3b4199a669 | |||
| 562901aedf | |||
| 793117ed63 | |||
| 5b783d6376 | |||
| d3f3528d1d | |||
| 3145935d6b | |||
| 25430333ba | |||
| 2ca2b32dd0 | |||
| a5dde78f08 | |||
| fd415f0b45 | |||
| 507722954c | |||
| 524d23d45d | |||
| e9ee6f5291 | |||
| 7e5342f41f | |||
| 18607e53cb | |||
| ed933b3f21 | |||
| 49fecbdc5e | |||
| f971126183 | |||
| d4ccb69ccc | |||
| 37b4e0de6c | |||
| 737f440c7f | |||
| cba3f1e374 | |||
| a70dde34da | |||
| 410b85b5c7 | |||
| 0ae012ba08 | |||
| fc4eb4152c | |||
| 4f3b5d8dcb | |||
| f76f70c7cf | |||
| 15d783e920 | |||
| 09e4fff5b1 | |||
| 2d89faa17c | |||
| dd9843aa21 | |||
| 882116e358 | |||
| f3adbae1ed | |||
| 278e239973 | |||
| fda803b46a | |||
| 01162e08b5 | |||
| a7ae197a55 | |||
| 3c72cb67d3 | |||
| 37bba4c0a6 | |||
| ab9d1f99fd | |||
| 45124e4d5c | |||
| 7681c43b14 | |||
| 7e43cd7d97 | |||
| c223fc1766 | |||
| 04297bb680 | |||
| 553292ffd0 | |||
| 57862846a2 | |||
| 8e270d3a99 | |||
| ae5cb09041 | |||
| 093b2288c3 | |||
| ffe17a471d | |||
| e9f901b82d | |||
| ed3004f8a0 | |||
| d97df080f9 | |||
| 0e5c7e08fc | |||
| 83523badb7 | |||
| 0a90994403 | |||
| 376906e0ae | |||
| 47c79a2f25 | |||
| 32988b0363 | |||
| 00c138ce9f | |||
| 5676c9e7eb | |||
| 3a469dc13e | |||
| d3c70f2206 | |||
| 14f1793b3e | |||
| 8cecb6b9f5 | |||
| 4a66c3c420 | |||
| c3c88633a5 | |||
| aeaf1199ec | |||
| d4f62f52db | |||
| 384fb76a1b | |||
| 4a04a32e0a | |||
| 196bd735d4 | |||
| 493bc653b5 | |||
| 3d209798c9 | |||
| dd0d61e97c | |||
| 4b9324ff76 | |||
| e81ed9a960 | |||
| 83f7a887b7 | |||
| ad2f1ac24e | |||
| 62d232d798 | |||
| 8906a0120c | |||
| cad753e398 | |||
| fd627dc13b | |||
| 70e8d97ee1 | |||
| cdecb0ccc3 | |||
| 460b5149af | |||
| b6dc253d8b | |||
| e7be9493ba | |||
| ea34f321ed | |||
| 2b5bc1d558 | |||
| e6a7b85da4 | |||
| 6145185478 | |||
| 6630d703f8 | |||
| 9c3cdc4620 | |||
| 345032f804 | |||
| 2abba6e057 | |||
| db5a1b0c78 | |||
| 14cb19c2df | |||
| 46bcd18946 | |||
| 3e5c60f746 | |||
| 0fa487f468 | |||
| 1bec9e5331 | |||
| ba61d911da | |||
| 3b69c6b204 | |||
| d7eabf571c | |||
| ddf9c4a65b | |||
| b3d797598e | |||
| 31c7945444 | |||
| 276e014d18 | |||
| 27f206784c | |||
| 54a6637d38 | |||
| 23be56af59 | |||
| 71df46456a | |||
| cd89d8a3c4 | |||
| 4c62a32b04 | |||
| 5f8137025d | |||
| 1843d52217 | |||
| 454c92dc64 | |||
| 7e33a86d54 | |||
| 197b832992 | |||
| 8f13724a4b | |||
| 746d5fc322 | |||
| ffc45e8cc2 | |||
| bea2f36443 | |||
| f138f71fa6 | |||
| 89b7a3f7ac | |||
| 75e15b05b0 | |||
| 78eb388110 | |||
| df23cf47c6 | |||
| 002ac6a1b7 | |||
| 40e4536887 | |||
| 536bf61323 | |||
| c76bdced55 | |||
| 459ea5f4f6 | |||
| 8e8a075a22 | |||
| db6bd9b358 | |||
| 42ad54c28e | |||
| 1857bc7b02 | |||
| e011d812ca | |||
| 0738822dda | |||
| 2213722776 | |||
| 65dedbb1ca | |||
| 0e69993d39 | |||
| 135091ddbe | |||
| d64e3b672c | |||
| a3bcacee27 | |||
| 855e7beab1 | |||
| edc13c29df | |||
| 21864d8d51 | |||
| d45ff0694d | |||
| d695a8a526 | |||
| 0380a288a9 | |||
| 1d4d0a3e1a | |||
| 9e98494fff | |||
| 86d334282c | |||
| 9cf937fef0 | |||
| f5697dd7f2 | |||
| a23ee1edc1 | |||
| 9dcb5c075a | |||
| 803648be89 | |||
| 3ab5db8297 | |||
| 3380ece4a1 | |||
| 0e5928ff39 | |||
| e6e04fc6c8 | |||
| 753cceea82 | |||
| 32c7e81745 | |||
| 03aec70287 | |||
| e69738c079 | |||
| 1afa7967f2 | |||
| 643e36b87b | |||
| 3d2405ac2c | |||
| 7392a3047a | |||
| 60f4d8f1ec | |||
| 7b42cbea20 | |||
| 4cc597f4df | |||
| 934e66ab3b | |||
| b755609438 | |||
| 83d63e572a | |||
| 5212f62f54 | |||
| 4d0fd4cf19 | |||
| e47953f7ca | |||
| 47f3773146 | |||
| 31c6ecad34 | |||
| af6e53c05c | |||
| 153140eb8f | |||
| 6fef44c041 | |||
| a88d149903 | |||
| f9fc488399 | |||
| bef806bef4 | |||
| 95e9bbf99f | |||
| 5936fa8871 | |||
| 02646b789c | |||
| 09e9dca869 | |||
| 9a43c0672e | |||
| 83a6169463 | |||
| debe2de5fe | |||
| ff7d591ebf | |||
| 7386ca9272 | |||
| fd8b2e0b88 | |||
| c34ae884ad | |||
| 2e7157ae9c | |||
| 441365b388 | |||
| f561147190 | |||
| 2958c1d6aa | |||
| 9dc83bc1b3 | |||
| 88b1b2c629 | |||
| 23bc643a81 | |||
| 41854bacf5 | |||
| cf528431f5 | |||
| e59064dd59 | |||
| 8966294823 | |||
| b8479ea79d | |||
| e2aa8f426d | |||
| 39a0f8c96a | |||
| b647b45ba5 | |||
| 5fe9aa919b | |||
| ff5d6a994b | |||
| ae3b95b194 | |||
| acaae1357c | |||
| f8afda3b22 | |||
| 31f544c258 | |||
| 1c57d1c019 | |||
| 251edf7bc7 | |||
| f77cd5533d | |||
| 416413bebf | |||
| c3809d7b84 | |||
| 42a1c58a80 | |||
| b6abaf739c | |||
| ef98e92e8d | |||
| 768c2684d0 | |||
| 5f2514db63 | |||
| b95ade40c0 | |||
| 340838c878 | |||
| c5d348515d | |||
| 05dd3d490d | |||
| 0cc40db565 | |||
| 546faab0cb | |||
| 83e9a6b417 | |||
| 30bb2382aa | |||
| 61a0b4ec5a | |||
| accb35506f | |||
| 817bc7434d | |||
| 3c2ed3bb69 | |||
| 9cbf46e689 | |||
| ad6ea3d6aa | |||
| cda9fd5271 | |||
| 0c16f27814 | |||
| 19aec13a10 | |||
| e896956275 | |||
| c59c6e98a5 | |||
| 8b1100bf2b | |||
| a3d99765cc | |||
| a724573bb3 | |||
| 25769f139a | |||
| 3edf638cc6 | |||
| de7e612186 | |||
| a571153458 | |||
| ada58c66fa | |||
| 697f8c7ee6 | |||
| b6ebfe4b2c | |||
| bccbdefde9 | |||
| 445ca70521 | |||
| c6ab8f82c8 | |||
| 67ce0ec29f | |||
| 23c3573c30 | |||
| a4308e7246 | |||
| 3439139b1c | |||
| cf246f65ff | |||
| dd84b61cc8 | |||
| b8c4bf2afb | |||
| e870041fe6 | |||
| 6418ec3b21 | |||
| 2bcc7b0064 | |||
| 97be867103 | |||
| fb710f8cbf | |||
| 1553137c23 | |||
| d5384c5aa4 | |||
| 3a81f2ab89 | |||
| b54fc96b1e | |||
| 48af78e469 | |||
| a315e7c962 | |||
| 42364f2fce | |||
| 8f600798ef | |||
| abb26e0bea | |||
| 76edfae0e0 | |||
| a5298e17ec | |||
| cf9f3d5e2d | |||
| 35c90fe124 | |||
| df8bdac33f | |||
| b4f7a527c2 | |||
| 35533a7baa | |||
| 2c9ed7464f | |||
| e190c024fd | |||
| e250475bf9 | |||
| 5db603ded2 | |||
| 78815778ee | |||
| a04d849e30 | |||
| 8c9505505a | |||
| eac74631ec | |||
| 85706d559d | |||
| 67ba05cb7c | |||
| 2f1aeaf757 | |||
| 14a17fb36f | |||
| 1a9ec776cb | |||
| da1edac56d | |||
| 44ec95a983 | |||
| 1502066303 | |||
| 35a826a0fd | |||
| ebb8ca7c26 | |||
| 763de44853 | |||
| 62cc752066 | |||
| 965b962b29 | |||
| 2f3c5336d9 | |||
| 3824937295 | |||
| fc8ddcef5c | |||
| 3165b7cf95 | |||
| 5eea23cf76 | |||
| 2aa783179e | |||
| 24e7356825 | |||
| 2fcba25e50 | |||
| 28bc274449 | |||
| ff5e036773 | |||
| 4dc29d141f | |||
| 8ecee32e1c | |||
| 16786aac78 | |||
| 32b37f3429 | |||
| 5808793cae | |||
| 7e11f3cc4b | |||
| 714ab516c5 | |||
| 498f68c06b | |||
| 070b450768 | |||
| 74174eb4ae | |||
| b190404b21 | |||
| 081a5a52a6 | |||
| fb86c23dbd | |||
| cb6a4ebf60 | |||
| 1bf8328606 | |||
| 6a7f39453b | |||
| 515fd2a228 | |||
| dd3322ac1f | |||
| f16f1d932e | |||
| a3e7b2baa1 | |||
| fadf9b5309 | |||
| f6a087775e | |||
| d5f7e181a0 | |||
| 65f8722afc | |||
| c0479f1564 | |||
| fe0b5bf4e2 | |||
| f20105ddfe | |||
| 6a7d821fcc | |||
| 42ab882db4 | |||
| f28c268d97 | |||
| f1cff20249 | |||
| dcc9e61362 | |||
| 2554c72bb2 | |||
| 49872e40dc | |||
| 849fe01e70 | |||
| 1243b1a58c | |||
| ab3bae5c02 | |||
| 540c5400a0 | |||
| d269dbcd40 | |||
| 18e639f59b | |||
| 6ad262c2df | |||
| 10b97a1b39 | |||
| 56b4e0a3c3 | |||
| 27dbe84f79 | |||
| 0711d4e5fe | |||
| 1e46537959 | |||
| a5e1693774 | |||
| 01e29bf27e | |||
| 63771bc6e8 | |||
| 8516e2e7e3 | |||
| b3c3e41706 | |||
| 59f3a009fa | |||
| 9bc5b84c4d | |||
| f9265c14bf | |||
| 9c1e1a63a2 | |||
| 4dc5839e3d | |||
| fdcb9deaff | |||
| fe6539fad9 | |||
| 0e06383620 | |||
| 6223f48c3f | |||
| f2f20def37 | |||
| 77b91352ae | |||
| 3d7d347192 | |||
| e5868e3205 | |||
| cfbc1a447b | |||
| 1b23dd2257 | |||
| b612edba5a | |||
| d39c05b183 | |||
| 3a3cb521ab | |||
| 5b97ff0b48 | |||
| 2b918ada4b | |||
| b5754b6ed9 | |||
| 07ee23f817 | |||
| ecdaac9921 | |||
| 5ff82fc113 | |||
| 28a816ef25 | |||
| 6bdb210ad8 | |||
| db08847f9a | |||
| 841c428273 | |||
| 6b830f42b6 | |||
| fb01dfe048 | |||
| c7a9c8274f | |||
| cafb6e5587 | |||
| e9ae6e20e8 | |||
| 2ca2dbcc92 | |||
| 0d4642825f | |||
| 8eda756714 | |||
| c85ac955f7 | |||
| 97922406fe | |||
| 76ccce2942 | |||
| 686dbb4421 | |||
| cd6898439e | |||
| 96d7c4ffdf | |||
| 95620aaf2a | |||
| 1d293749c2 | |||
| 2d35a5c1af | |||
| d4ea02a877 | |||
| f19325cbe0 | |||
| 2a325b3da0 | |||
| d57ec4a11d | |||
| f0529535e0 | |||
| 3f59c45740 | |||
| 29ebe0c3c9 | |||
| 6c48670819 | |||
| 51dcbc80c3 | |||
| 9ecbadd457 | |||
| 79f32d7b71 | |||
| 7501cc2f17 | |||
| a390ef41f8 | |||
| bb9c2f7aad | |||
| 6aa80ee8e4 | |||
| 0741bc37cc | |||
| c6ed3fa4b5 | |||
| e277102947 | |||
| 6cf5371d7d | |||
| e15f714660 | |||
| 4f77151ebc | |||
| 9a46463078 | |||
| a0816bb581 | |||
| b33ca6651e | |||
| 315a08f33f | |||
| 50668fa7a6 | |||
| ee260986a9 | |||
| c9bc759624 | |||
| 80f175cdb0 | |||
| 8f03811842 | |||
| 3def94505e | |||
| e30f16b1f3 | |||
| 7df93ea504 | |||
| 6209b02bf9 | |||
| 75b7f2b9fe | |||
| f1521aa980 | |||
| fb0a3ab7c1 | |||
| 8eaafd5242 | |||
| 774951e8c0 | |||
| 5ec93677a0 | |||
| 7e4067c44c | |||
| f2f6c3c67d | |||
| 847b05013f | |||
| d308473075 | |||
| 4334dbe69a | |||
| 8f91e9307c | |||
| 32ec1162bf | |||
| 7cc265e14c | |||
| 6f3e450c50 | |||
| cb1080d56c | |||
| 80bd1eb615 | |||
| fb53402914 | |||
| 731853ce78 | |||
| f0260e9771 | |||
| af612bc7e9 | |||
| d76dd95c0b | |||
| 1cff72ad62 | |||
| 773cfac449 | |||
| b02f2953ac | |||
| 566a750899 | |||
| 1d1d684cbc | |||
| 7a14acaa01 | |||
| 057174497a | |||
| 8c9597b24b | |||
| 72862ce30d | |||
| d0f4cb1de4 | |||
| 17613185e7 | |||
| 00ff1fbca2 | |||
| f15bb0b424 | |||
| f818d0feb1 | |||
| 8ff6f95571 | |||
| 68e5f57e27 | |||
| 38e5e13b3f | |||
| defc1672c3 | |||
| 12f459b5fb | |||
| e6b8f7e77a | |||
| 236b08cb49 | |||
| e4f28de3de | |||
| 750ee4ecdb | |||
| 865d88dd56 | |||
| 92e70b9a58 | |||
| 822da9d12d | |||
| 069c05669f | |||
| 516065d7c2 | |||
| 5d80e24224 | |||
| ebdb3ab43a | |||
| 29ca6ee420 | |||
| 6e61abc7d0 | |||
| 7ec88d2430 | |||
| d7200f6144 | |||
| d65d6edb0e | |||
| 3d72e80ccf | |||
| 2dd67dba89 | |||
| 5807214406 | |||
| 23baf56c87 | |||
| beff90e1d1 | |||
| ec63d0bbd2 | |||
| 32eab04d66 | |||
| 682783a2aa | |||
| 46a4927aca | |||
| 9b2e67df67 | |||
| b5c828fe4e | |||
| a4ba91a554 | |||
| cf390bf8b9 |
@@ -1,3 +1,4 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: odin-lang
|
||||||
patreon: gingerbill
|
patreon: gingerbill
|
||||||
|
|||||||
+64
-14
@@ -1,5 +1,5 @@
|
|||||||
name: CI
|
name: CI
|
||||||
on: [push, pull_request]
|
on: [push, pull_request, workflow_dispatch]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_linux:
|
build_linux:
|
||||||
@@ -7,9 +7,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: Download LLVM, botan
|
- name: Download LLVM, botan
|
||||||
run: sudo apt-get install llvm-11 clang-11 llvm libbotan-2-dev botan
|
run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan
|
||||||
- name: build odin
|
- name: build odin
|
||||||
run: make release
|
run: ./build_odin.sh release
|
||||||
- name: Odin version
|
- name: Odin version
|
||||||
run: ./odin version
|
run: ./odin version
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
@@ -17,13 +17,16 @@ jobs:
|
|||||||
run: ./odin report
|
run: ./odin report
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
- name: Odin check
|
- name: Odin check
|
||||||
run: ./odin check examples/demo/demo.odin -vet
|
run: ./odin check examples/demo -vet
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
run: ./odin run examples/demo/demo.odin
|
run: ./odin run examples/demo
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run -debug
|
- name: Odin run -debug
|
||||||
run: ./odin run examples/demo/demo.odin -debug
|
run: ./odin run examples/demo -debug
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all
|
||||||
|
run: ./odin check examples/all -strict-style
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Core library tests
|
- name: Core library tests
|
||||||
run: |
|
run: |
|
||||||
@@ -35,6 +38,20 @@ jobs:
|
|||||||
cd tests/vendor
|
cd tests/vendor
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin issues tests
|
||||||
|
run: |
|
||||||
|
cd tests/issues
|
||||||
|
./run.sh
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Linux i386
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for FreeBSD amd64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for OpenBSD amd64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
|
||||||
|
timeout-minutes: 10
|
||||||
build_macOS:
|
build_macOS:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -46,7 +63,7 @@ jobs:
|
|||||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||||
- name: build odin
|
- name: build odin
|
||||||
run: make release
|
run: ./build_odin.sh release
|
||||||
- name: Odin version
|
- name: Odin version
|
||||||
run: ./odin version
|
run: ./odin version
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
@@ -54,13 +71,16 @@ jobs:
|
|||||||
run: ./odin report
|
run: ./odin report
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
- name: Odin check
|
- name: Odin check
|
||||||
run: ./odin check examples/demo/demo.odin -vet
|
run: ./odin check examples/demo -vet
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
run: ./odin run examples/demo/demo.odin
|
run: ./odin run examples/demo
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run -debug
|
- name: Odin run -debug
|
||||||
run: ./odin run examples/demo/demo.odin -debug
|
run: ./odin run examples/demo -debug
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all
|
||||||
|
run: ./odin check examples/all -strict-style
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Core library tests
|
- name: Core library tests
|
||||||
run: |
|
run: |
|
||||||
@@ -72,8 +92,19 @@ jobs:
|
|||||||
cd tests/vendor
|
cd tests/vendor
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin issues tests
|
||||||
|
run: |
|
||||||
|
cd tests/issues
|
||||||
|
./run.sh
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Darwin arm64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Linux arm64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||||
|
timeout-minutes: 10
|
||||||
build_windows:
|
build_windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: build Odin
|
- name: build Odin
|
||||||
@@ -91,19 +122,25 @@ jobs:
|
|||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin check examples/demo/demo.odin -vet
|
odin check examples/demo -vet
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin run examples/demo/demo.odin
|
odin run examples/demo
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin run -debug
|
- name: Odin run -debug
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin run examples/demo/demo.odin -debug
|
odin run examples/demo -debug
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
|
odin check examples/all -strict-style
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Core library tests
|
- name: Core library tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@@ -126,3 +163,16 @@ jobs:
|
|||||||
cd tests\core\math\big
|
cd tests\core\math\big
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin issues tests
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
|
cd tests\issues
|
||||||
|
call run.bat
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Windows 32bits
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
|
odin check examples/all -strict-style -target:windows_i386
|
||||||
|
timeout-minutes: 10
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_windows:
|
build_windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: build Odin
|
- name: build Odin
|
||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
odin run examples/demo/demo.odin
|
odin run examples/demo
|
||||||
- name: Copy artifacts
|
- name: Copy artifacts
|
||||||
run: |
|
run: |
|
||||||
rm bin/llvm/windows/LLVM-C.lib
|
rm bin/llvm/windows/LLVM-C.lib
|
||||||
@@ -41,11 +41,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: (Linux) Download LLVM
|
- name: (Linux) Download LLVM
|
||||||
run: sudo apt-get install llvm-11 clang-11 llvm
|
run: sudo apt-get install llvm-11 clang-11
|
||||||
- name: build odin
|
- name: build odin
|
||||||
run: make nightly
|
run: make nightly
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
run: ./odin run examples/demo/demo.odin
|
run: ./odin run examples/demo
|
||||||
- name: Copy artifacts
|
- name: Copy artifacts
|
||||||
run: |
|
run: |
|
||||||
mkdir dist
|
mkdir dist
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
- name: build odin
|
- name: build odin
|
||||||
run: make nightly
|
run: make nightly
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
run: ./odin run examples/demo/demo.odin
|
run: ./odin run examples/demo
|
||||||
- name: Copy artifacts
|
- name: Copy artifacts
|
||||||
run: |
|
run: |
|
||||||
mkdir dist
|
mkdir dist
|
||||||
@@ -129,7 +129,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo Authorizing B2 account
|
echo Authorizing B2 account
|
||||||
b2 authorize-account "$APPID" "$APPKEY"
|
b2 authorize-account "$APPID" "$APPKEY"
|
||||||
|
|
||||||
echo Uploading artifcates to B2
|
echo Uploading artifcates to B2
|
||||||
chmod +x ./ci/upload_create_nightly.sh
|
chmod +x ./ci/upload_create_nightly.sh
|
||||||
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
|
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
|
||||||
@@ -141,7 +141,7 @@ jobs:
|
|||||||
|
|
||||||
echo Creating nightly.json
|
echo Creating nightly.json
|
||||||
python3 ci/create_nightly_json.py "$BUCKET" > nightly.json
|
python3 ci/create_nightly_json.py "$BUCKET" > nightly.json
|
||||||
|
|
||||||
echo Uploading nightly.json
|
echo Uploading nightly.json
|
||||||
b2 upload-file "$BUCKET" nightly.json nightly.json
|
b2 upload-file "$BUCKET" nightly.json nightly.json
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: "Close Stale Issues & PRs"
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 21 * * *"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Close Stale Issues
|
||||||
|
uses: actions/stale@v4.1.0
|
||||||
|
with:
|
||||||
|
# stale-issue-message: |
|
||||||
|
# Hello!
|
||||||
|
#
|
||||||
|
# I am marking this issue as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
|
||||||
|
# - open a PR referencing and resolving the issue;
|
||||||
|
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
|
||||||
|
# - leave a comment and describe in detail why this issue is critical for your use case;
|
||||||
|
# - open a new issue with updated details and a plan on resolving the issue.
|
||||||
|
#
|
||||||
|
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||||
|
#
|
||||||
|
# stale-pr-message: |
|
||||||
|
# Hello!
|
||||||
|
#
|
||||||
|
# I am marking this PR as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
|
||||||
|
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
|
||||||
|
# - leave a comment and describe in detail why this issue is critical for your use case;
|
||||||
|
#
|
||||||
|
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||||
|
|
||||||
|
days-before-stale: 120
|
||||||
|
days-before-close: 30
|
||||||
|
exempt-draft-pr: true
|
||||||
|
ascending: true
|
||||||
|
operations-per-run: 1000
|
||||||
|
exempt-issue-labels: "ignore"
|
||||||
@@ -7,6 +7,9 @@
|
|||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
|
# For macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
@@ -266,6 +269,8 @@ bin/
|
|||||||
# - Linux/MacOS
|
# - Linux/MacOS
|
||||||
odin
|
odin
|
||||||
odin.dSYM
|
odin.dSYM
|
||||||
|
*.bin
|
||||||
|
demo.bin
|
||||||
|
|
||||||
# shared collection
|
# shared collection
|
||||||
shared/
|
shared/
|
||||||
@@ -276,3 +281,5 @@ shared/
|
|||||||
*.ll
|
*.ll
|
||||||
|
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
examples/bug/
|
||||||
|
build.sh
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2016-2021 Ginger Bill. All rights reserved.
|
Copyright (c) 2016-2022 Ginger Bill. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|||||||
@@ -1,68 +1,19 @@
|
|||||||
GIT_SHA=$(shell git rev-parse --short HEAD)
|
all: debug
|
||||||
DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value
|
|
||||||
LDFLAGS=-pthread -ldl -lm -lstdc++
|
|
||||||
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
|
|
||||||
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
|
|
||||||
CC=clang
|
|
||||||
|
|
||||||
OS=$(shell uname)
|
|
||||||
|
|
||||||
ifeq ($(OS), Darwin)
|
|
||||||
ARCH=$(shell uname -m)
|
|
||||||
LLVM_CONFIG=llvm-config
|
|
||||||
|
|
||||||
# LLVM Version Setting
|
|
||||||
LLVM_VERSION_PATTERN="^11\."
|
|
||||||
LLVM_VERSION="11"
|
|
||||||
ifeq ($(ARCH), arm64)
|
|
||||||
LLVM_VERSION="13"
|
|
||||||
LLVM_VERSION_PATTERN="^13"
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(shell llvm-config --version | grep $(LLVM_VERSION_PATTERN)),)
|
|
||||||
LLVM_CONFIG=llvm-config
|
|
||||||
else
|
|
||||||
$(error "Requirement: llvm-config must be version $(LLVM_VERSION)")
|
|
||||||
endif
|
|
||||||
|
|
||||||
LDFLAGS:=$(LDFLAGS) -liconv
|
|
||||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
|
||||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
|
||||||
endif
|
|
||||||
ifeq ($(OS), Linux)
|
|
||||||
LLVM_CONFIG=llvm-config-11
|
|
||||||
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
|
||||||
LLVM_CONFIG=llvm-config-11
|
|
||||||
else ifneq ($(shell which llvm-config-11-64 2>/dev/null),)
|
|
||||||
LLVM_CONFIG=llvm-config-11-64
|
|
||||||
else
|
|
||||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
|
||||||
LLVM_CONFIG=llvm-config
|
|
||||||
else
|
|
||||||
$(error "Requirement: llvm-config must be version 11")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
|
||||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: debug demo
|
|
||||||
|
|
||||||
demo:
|
demo:
|
||||||
./odin run examples/demo/demo.odin
|
./odin run examples/demo/demo.odin -file
|
||||||
|
|
||||||
report:
|
report:
|
||||||
./odin report
|
./odin report
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
./build_odin.sh debug
|
||||||
|
|
||||||
release:
|
release:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 $(LDFLAGS) -o odin
|
./build_odin.sh release
|
||||||
|
|
||||||
release_native:
|
release_native:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
|
./build_odin.sh release-native
|
||||||
|
|
||||||
nightly:
|
nightly:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
./build_odin.sh nightly
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://discord.gg/hnwN2Rj">
|
<a href="https://discord.gg/odinlang">
|
||||||
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/odin-lang/odin/actions">
|
<a href="https://github.com/odin-lang/odin/actions">
|
||||||
@@ -58,6 +58,10 @@ main :: proc() {
|
|||||||
|
|
||||||
Instructions for downloading and installing the Odin compiler and libraries.
|
Instructions for downloading and installing the Odin compiler and libraries.
|
||||||
|
|
||||||
|
#### [Nightly Builds](https://odin-lang.org/docs/nightly/)
|
||||||
|
|
||||||
|
Get the latest nightly builds of Odin.
|
||||||
|
|
||||||
### Learning Odin
|
### Learning Odin
|
||||||
|
|
||||||
#### [Overview of Odin](https://odin-lang.org/docs/overview)
|
#### [Overview of Odin](https://odin-lang.org/docs/overview)
|
||||||
@@ -68,6 +72,10 @@ An overview of the Odin programming language.
|
|||||||
|
|
||||||
Answers to common questions about Odin.
|
Answers to common questions about Odin.
|
||||||
|
|
||||||
|
#### [Packages](https://pkg.odin-lang.org/)
|
||||||
|
|
||||||
|
Documentation for all the official packages part of the [core](https://pkg.odin-lang.org/core/) and [vendor](https://pkg.odin-lang.org/vendor/) library collections.
|
||||||
|
|
||||||
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
|
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
|
||||||
|
|
||||||
A wiki maintained by the Odin community.
|
A wiki maintained by the Odin community.
|
||||||
@@ -76,15 +84,9 @@ A wiki maintained by the Odin community.
|
|||||||
|
|
||||||
Get live support and talk with other odiners on the Odin Discord.
|
Get live support and talk with other odiners on the Odin Discord.
|
||||||
|
|
||||||
### References
|
|
||||||
|
|
||||||
#### [Language Specification](https://odin-lang.org/docs/spec/)
|
|
||||||
|
|
||||||
The official Odin Language specification.
|
|
||||||
|
|
||||||
### Articles
|
### Articles
|
||||||
|
|
||||||
#### [The Odin Blog](https://odin-lang.org/blog)
|
#### [The Odin Blog](https://odin-lang.org/news/)
|
||||||
|
|
||||||
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
|
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ set libs= ^
|
|||||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||||
|
|
||||||
if %release_mode% EQU 0 ( rem Debug
|
if %release_mode% EQU 0 ( rem Debug
|
||||||
set linker_flags=%linker_flags% -debug
|
set linker_flags=%linker_flags% -debug /NATVIS:src\odin_compiler.natvis
|
||||||
) else ( rem Release
|
) else ( rem Release
|
||||||
set linker_flags=%linker_flags% -debug
|
set linker_flags=%linker_flags% -debug
|
||||||
)
|
)
|
||||||
|
|||||||
Executable
+162
@@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
: ${CXX=clang++}
|
||||||
|
: ${CPPFLAGS=}
|
||||||
|
: ${CXXFLAGS=}
|
||||||
|
: ${LDFLAGS=}
|
||||||
|
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
|
||||||
|
|
||||||
|
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
|
||||||
|
CXXFLAGS="$CXXFLAGS -std=c++14"
|
||||||
|
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
||||||
|
|
||||||
|
GIT_SHA=$(git rev-parse --short HEAD || :)
|
||||||
|
if [ "$GIT_SHA" ]; then CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""; fi
|
||||||
|
|
||||||
|
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
|
||||||
|
OS=$(uname)
|
||||||
|
|
||||||
|
panic() {
|
||||||
|
printf "%s\n" "$1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
|
||||||
|
|
||||||
|
config_darwin() {
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
: ${LLVM_CONFIG=llvm-config}
|
||||||
|
|
||||||
|
# allow for arm only llvm's with version 13
|
||||||
|
if [ ARCH == arm64 ]; then
|
||||||
|
MIN_LLVM_VERSION=("13.0.0")
|
||||||
|
else
|
||||||
|
# allow for x86 / amd64 all llvm versions beginning from 11
|
||||||
|
MIN_LLVM_VERSION=("11.1.0")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||||
|
if [ ARCH == arm64 ]; then
|
||||||
|
panic "Requirement: llvm-config must be base version 13 for arm64"
|
||||||
|
else
|
||||||
|
panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||||
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||||
|
}
|
||||||
|
|
||||||
|
config_freebsd() {
|
||||||
|
: ${LLVM_CONFIG=/usr/local/bin/llvm-config11}
|
||||||
|
|
||||||
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||||
|
}
|
||||||
|
|
||||||
|
config_openbsd() {
|
||||||
|
: ${LLVM_CONFIG=/usr/local/bin/llvm-config}
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS -liconv"
|
||||||
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||||
|
}
|
||||||
|
|
||||||
|
config_linux() {
|
||||||
|
: ${LLVM_CONFIG=}
|
||||||
|
|
||||||
|
if [ ! "$LLVM_CONFIG" ]; then
|
||||||
|
if which llvm-config > /dev/null 2>&1; then
|
||||||
|
LLVM_CONFIG=llvm-config
|
||||||
|
elif which llvm-config-11 > /dev/null 2>&1; then
|
||||||
|
LLVM_CONFIG=llvm-config-11
|
||||||
|
elif which llvm-config-11-64 > /dev/null 2>&1; then
|
||||||
|
LLVM_CONFIG=llvm-config-11-64
|
||||||
|
else
|
||||||
|
panic "Unable to find LLVM-config"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
MIN_LLVM_VERSION=("11.0.0")
|
||||||
|
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||||
|
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
|
||||||
|
panic "Requirement: llvm-config must be base version greater than 11"
|
||||||
|
fi
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS -ldl"
|
||||||
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_odin() {
|
||||||
|
case $1 in
|
||||||
|
debug)
|
||||||
|
EXTRAFLAGS="-g"
|
||||||
|
;;
|
||||||
|
release)
|
||||||
|
EXTRAFLAGS="-O3"
|
||||||
|
;;
|
||||||
|
release-native)
|
||||||
|
EXTRAFLAGS="-O3 -march=native"
|
||||||
|
;;
|
||||||
|
nightly)
|
||||||
|
EXTRAFLAGS="-DNIGHTLY -O3"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
panic "Build mode unsupported!"
|
||||||
|
esac
|
||||||
|
|
||||||
|
set -x
|
||||||
|
$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||||
|
set +x
|
||||||
|
}
|
||||||
|
|
||||||
|
run_demo() {
|
||||||
|
./odin run examples/demo/demo.odin -file
|
||||||
|
}
|
||||||
|
|
||||||
|
case $OS in
|
||||||
|
Linux)
|
||||||
|
config_linux
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
config_darwin
|
||||||
|
;;
|
||||||
|
OpenBSD)
|
||||||
|
config_openbsd
|
||||||
|
;;
|
||||||
|
FreeBSD)
|
||||||
|
config_freebsd
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
panic "Platform unsupported!"
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
build_odin debug
|
||||||
|
run_demo
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $# -eq 1 ]]; then
|
||||||
|
case $1 in
|
||||||
|
report)
|
||||||
|
if [[ ! -f "./odin" ]]; then
|
||||||
|
build_odin debug
|
||||||
|
fi
|
||||||
|
|
||||||
|
./odin report
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
build_odin $1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
run_demo
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
panic "Too many arguments!"
|
||||||
|
fi
|
||||||
@@ -8,6 +8,7 @@ import "core:intrinsics"
|
|||||||
|
|
||||||
// Extra errors returns by scanning procedures
|
// Extra errors returns by scanning procedures
|
||||||
Scanner_Extra_Error :: enum i32 {
|
Scanner_Extra_Error :: enum i32 {
|
||||||
|
None,
|
||||||
Negative_Advance,
|
Negative_Advance,
|
||||||
Advanced_Too_Far,
|
Advanced_Too_Far,
|
||||||
Bad_Read_Count,
|
Bad_Read_Count,
|
||||||
@@ -15,7 +16,7 @@ Scanner_Extra_Error :: enum i32 {
|
|||||||
Too_Short,
|
Too_Short,
|
||||||
}
|
}
|
||||||
|
|
||||||
Scanner_Error :: union {
|
Scanner_Error :: union #shared_nil {
|
||||||
io.Error,
|
io.Error,
|
||||||
Scanner_Extra_Error,
|
Scanner_Extra_Error,
|
||||||
}
|
}
|
||||||
@@ -65,10 +66,10 @@ scanner_destroy :: proc(s: ^Scanner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns the first non-EOF error that was encounted by the scanner
|
// Returns the first non-EOF error that was encountered by the scanner
|
||||||
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
|
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
|
||||||
switch s._err {
|
switch s._err {
|
||||||
case .EOF, .None:
|
case .EOF, nil:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return s._err
|
return s._err
|
||||||
@@ -93,10 +94,6 @@ scanner_text :: proc(s: ^Scanner) -> string {
|
|||||||
// scanner_scan advances the scanner
|
// scanner_scan advances the scanner
|
||||||
scanner_scan :: proc(s: ^Scanner) -> bool {
|
scanner_scan :: proc(s: ^Scanner) -> bool {
|
||||||
set_err :: proc(s: ^Scanner, err: Scanner_Error) {
|
set_err :: proc(s: ^Scanner, err: Scanner_Error) {
|
||||||
err := err
|
|
||||||
if err == .None {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
switch s._err {
|
switch s._err {
|
||||||
case nil, .EOF:
|
case nil, .EOF:
|
||||||
s._err = err
|
s._err = err
|
||||||
|
|||||||
+66
-66
@@ -1,90 +1,90 @@
|
|||||||
// This is purely for documentation
|
// This is purely for documentation
|
||||||
package builtin
|
package builtin
|
||||||
|
|
||||||
nil :: nil;
|
nil :: nil
|
||||||
false :: 0!==0;
|
false :: 0!=0
|
||||||
true :: 0==0;
|
true :: 0==0
|
||||||
|
|
||||||
ODIN_OS :: ODIN_OS;
|
ODIN_OS :: ODIN_OS
|
||||||
ODIN_ARCH :: ODIN_ARCH;
|
ODIN_ARCH :: ODIN_ARCH
|
||||||
ODIN_ENDIAN :: ODIN_ENDIAN;
|
ODIN_ENDIAN :: ODIN_ENDIAN
|
||||||
ODIN_VENDOR :: ODIN_VENDOR;
|
ODIN_VENDOR :: ODIN_VENDOR
|
||||||
ODIN_VERSION :: ODIN_VERSION;
|
ODIN_VERSION :: ODIN_VERSION
|
||||||
ODIN_ROOT :: ODIN_ROOT;
|
ODIN_ROOT :: ODIN_ROOT
|
||||||
ODIN_DEBUG :: ODIN_DEBUG;
|
ODIN_DEBUG :: ODIN_DEBUG
|
||||||
|
|
||||||
byte :: u8; // alias
|
byte :: u8 // alias
|
||||||
|
|
||||||
bool :: bool;
|
bool :: bool
|
||||||
b8 :: b8;
|
b8 :: b8
|
||||||
b16 :: b16;
|
b16 :: b16
|
||||||
b32 :: b32;
|
b32 :: b32
|
||||||
b64 :: b64;
|
b64 :: b64
|
||||||
|
|
||||||
i8 :: i8;
|
i8 :: i8
|
||||||
u8 :: u8;
|
u8 :: u8
|
||||||
i16 :: i16;
|
i16 :: i16
|
||||||
u16 :: u16;
|
u16 :: u16
|
||||||
i32 :: i32;
|
i32 :: i32
|
||||||
u32 :: u32;
|
u32 :: u32
|
||||||
i64 :: i64;
|
i64 :: i64
|
||||||
u64 :: u64;
|
u64 :: u64
|
||||||
|
|
||||||
i128 :: i128;
|
i128 :: i128
|
||||||
u128 :: u128;
|
u128 :: u128
|
||||||
|
|
||||||
rune :: rune;
|
rune :: rune
|
||||||
|
|
||||||
f16 :: f16;
|
f16 :: f16
|
||||||
f32 :: f32;
|
f32 :: f32
|
||||||
f64 :: f64;
|
f64 :: f64
|
||||||
|
|
||||||
complex32 :: complex32;
|
complex32 :: complex32
|
||||||
complex64 :: complex64;
|
complex64 :: complex64
|
||||||
complex128 :: complex128;
|
complex128 :: complex128
|
||||||
|
|
||||||
quaternion64 :: quaternion64;
|
quaternion64 :: quaternion64
|
||||||
quaternion128 :: quaternion128;
|
quaternion128 :: quaternion128
|
||||||
quaternion256 :: quaternion256;
|
quaternion256 :: quaternion256
|
||||||
|
|
||||||
int :: int;
|
int :: int
|
||||||
uint :: uint;
|
uint :: uint
|
||||||
uintptr :: uintptr;
|
uintptr :: uintptr
|
||||||
|
|
||||||
rawptr :: rawptr;
|
rawptr :: rawptr
|
||||||
string :: string;
|
string :: string
|
||||||
cstring :: cstring;
|
cstring :: cstring
|
||||||
any :: any;
|
any :: any
|
||||||
|
|
||||||
typeid :: typeid;
|
typeid :: typeid
|
||||||
|
|
||||||
// Endian Specific Types
|
// Endian Specific Types
|
||||||
i16le :: i16le;
|
i16le :: i16le
|
||||||
u16le :: u16le;
|
u16le :: u16le
|
||||||
i32le :: i32le;
|
i32le :: i32le
|
||||||
u32le :: u32le;
|
u32le :: u32le
|
||||||
i64le :: i64le;
|
i64le :: i64le
|
||||||
u64le :: u64le;
|
u64le :: u64le
|
||||||
i128le :: i128le;
|
i128le :: i128le
|
||||||
u128le :: u128le;
|
u128le :: u128le
|
||||||
|
|
||||||
i16be :: i16be;
|
i16be :: i16be
|
||||||
u16be :: u16be;
|
u16be :: u16be
|
||||||
i32be :: i32be;
|
i32be :: i32be
|
||||||
u32be :: u32be;
|
u32be :: u32be
|
||||||
i64be :: i64be;
|
i64be :: i64be
|
||||||
u64be :: u64be;
|
u64be :: u64be
|
||||||
i128be :: i128be;
|
i128be :: i128be
|
||||||
u128be :: u128be;
|
u128be :: u128be
|
||||||
|
|
||||||
|
|
||||||
f16le :: f16le;
|
f16le :: f16le
|
||||||
f32le :: f32le;
|
f32le :: f32le
|
||||||
f64le :: f64le;
|
f64le :: f64le
|
||||||
|
|
||||||
f16be :: f16be;
|
f16be :: f16be
|
||||||
f32be :: f32be;
|
f32be :: f32be
|
||||||
f64be :: f64be;
|
f64be :: f64be
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
|
|||||||
return copy(b.buf[m:], p), nil
|
return copy(b.buf[m:], p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
|
||||||
|
return buffer_write(b, ([^]byte)(ptr)[:size])
|
||||||
|
}
|
||||||
|
|
||||||
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
|
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
|
||||||
b.last_read = .Invalid
|
b.last_read = .Invalid
|
||||||
m, ok := _buffer_try_grow(b, len(s))
|
m, ok := _buffer_try_grow(b, len(s))
|
||||||
@@ -229,6 +233,10 @@ buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
|
||||||
|
return buffer_read(b, ([^]byte)(ptr)[:size])
|
||||||
|
}
|
||||||
|
|
||||||
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
|
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
|
||||||
b.last_read = .Invalid
|
b.last_read = .Invalid
|
||||||
|
|
||||||
|
|||||||
+56
-36
@@ -10,7 +10,14 @@ clone :: proc(s: []byte, allocator := context.allocator, loc := #caller_location
|
|||||||
return c[:len(s)]
|
return c[:len(s)]
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_from_slice :: proc(str: []byte) -> ^byte {
|
clone_safe :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: mem.Allocator_Error) {
|
||||||
|
c := make([]byte, len(s), allocator, loc) or_return
|
||||||
|
copy(c, s)
|
||||||
|
return c[:len(s)], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr_from_slice :: ptr_from_bytes
|
||||||
|
ptr_from_bytes :: proc(str: []byte) -> ^byte {
|
||||||
d := transmute(mem.Raw_String)str
|
d := transmute(mem.Raw_String)str
|
||||||
return d.data
|
return d.data
|
||||||
}
|
}
|
||||||
@@ -134,6 +141,25 @@ join :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> []byte
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
join_safe :: proc(a: [][]byte, sep: []byte, allocator := context.allocator) -> (data: []byte, err: mem.Allocator_Error) {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n := len(sep) * (len(a) - 1)
|
||||||
|
for s in a {
|
||||||
|
n += len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, n, allocator) or_return
|
||||||
|
i := copy(b, a[0])
|
||||||
|
for s in a[1:] {
|
||||||
|
i += copy(b[i:], sep)
|
||||||
|
i += copy(b[i:], s)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte {
|
concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte {
|
||||||
if len(a) == 0 {
|
if len(a) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -151,6 +177,24 @@ concatenate :: proc(a: [][]byte, allocator := context.allocator) -> []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
concatenate_safe :: proc(a: [][]byte, allocator := context.allocator) -> (data: []byte, err: mem.Allocator_Error) {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n := 0
|
||||||
|
for s in a {
|
||||||
|
n += len(s)
|
||||||
|
}
|
||||||
|
b := make([]byte, n, allocator) or_return
|
||||||
|
i := 0
|
||||||
|
for s in a {
|
||||||
|
i += copy(b[i:], s)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@private
|
@private
|
||||||
_split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) -> [][]byte {
|
_split :: proc(s, sep: []byte, sep_save, n: int, allocator := context.allocator) -> [][]byte {
|
||||||
s, n := s, n
|
s, n := s, n
|
||||||
@@ -218,61 +262,37 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) ->
|
|||||||
|
|
||||||
|
|
||||||
@private
|
@private
|
||||||
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) {
|
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save: int) -> (res: []byte, ok: bool) {
|
||||||
s, n := s, n
|
if len(sep) == 0 {
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if sep == nil {
|
|
||||||
res = s[:]
|
res = s[:]
|
||||||
ok = true
|
ok = true
|
||||||
s^ = s[len(s):]
|
s^ = s[len(s):]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < 0 {
|
m := index(s^, sep)
|
||||||
n = count(s^, sep) + 1
|
if m < 0 {
|
||||||
}
|
// not found
|
||||||
|
res = s[:]
|
||||||
n -= 1
|
ok = len(res) != 0
|
||||||
|
s^ = s[len(s):]
|
||||||
i := 0
|
} else {
|
||||||
for ; i < n; i += 1 {
|
|
||||||
m := index(s^, sep)
|
|
||||||
if m < 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
res = s[:m+sep_save]
|
res = s[:m+sep_save]
|
||||||
ok = true
|
ok = true
|
||||||
s^ = s[m+len(sep):]
|
s^ = s[m+len(sep):]
|
||||||
return
|
|
||||||
}
|
}
|
||||||
res = s[:]
|
|
||||||
ok = res != nil
|
|
||||||
s^ = s[len(s):]
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||||
return _split_iterator(s, sep, 0, -1)
|
return _split_iterator(s, sep, 0)
|
||||||
}
|
|
||||||
|
|
||||||
split_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
|
||||||
return _split_iterator(s, sep, 0, n)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||||
return _split_iterator(s, sep, len(sep), -1)
|
return _split_iterator(s, sep, len(sep))
|
||||||
}
|
}
|
||||||
|
|
||||||
split_after_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
|
||||||
return _split_iterator(s, sep, len(sep), n)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
index_byte :: proc(s: []byte, c: byte) -> int {
|
index_byte :: proc(s: []byte, c: byte) -> int {
|
||||||
for i := 0; i < len(s); i += 1 {
|
for i := 0; i < len(s); i += 1 {
|
||||||
|
|||||||
+6
-4
@@ -3,22 +3,24 @@ package c
|
|||||||
import builtin "core:builtin"
|
import builtin "core:builtin"
|
||||||
|
|
||||||
char :: builtin.u8 // assuming -funsigned-char
|
char :: builtin.u8 // assuming -funsigned-char
|
||||||
|
|
||||||
|
schar :: builtin.i8
|
||||||
short :: builtin.i16
|
short :: builtin.i16
|
||||||
int :: builtin.i32
|
int :: builtin.i32
|
||||||
long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64
|
long :: builtin.i32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||||
longlong :: builtin.i64
|
longlong :: builtin.i64
|
||||||
|
|
||||||
uchar :: builtin.u8
|
uchar :: builtin.u8
|
||||||
ushort :: builtin.u16
|
ushort :: builtin.u16
|
||||||
uint :: builtin.u32
|
uint :: builtin.u32
|
||||||
ulong :: builtin.u32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.u64
|
ulong :: builtin.u32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.u64
|
||||||
ulonglong :: builtin.u64
|
ulonglong :: builtin.u64
|
||||||
|
|
||||||
bool :: builtin.bool
|
bool :: builtin.bool
|
||||||
|
|
||||||
size_t :: builtin.uint
|
size_t :: builtin.uint
|
||||||
ssize_t :: builtin.int
|
ssize_t :: builtin.int
|
||||||
wchar_t :: builtin.u16 when (ODIN_OS == "windows") else builtin.u32
|
wchar_t :: builtin.u16 when (ODIN_OS == .Windows) else builtin.u32
|
||||||
|
|
||||||
float :: builtin.f32
|
float :: builtin.f32
|
||||||
double :: builtin.f64
|
double :: builtin.f64
|
||||||
@@ -46,7 +48,7 @@ int_least64_t :: builtin.i64
|
|||||||
uint_least64_t :: builtin.u64
|
uint_least64_t :: builtin.u64
|
||||||
|
|
||||||
// Same on Windows, Linux, and FreeBSD
|
// Same on Windows, Linux, and FreeBSD
|
||||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||||
int_fast8_t :: builtin.i8
|
int_fast8_t :: builtin.i8
|
||||||
uint_fast8_t :: builtin.u8
|
uint_fast8_t :: builtin.u8
|
||||||
int_fast16_t :: builtin.i32
|
int_fast16_t :: builtin.i32
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ join_adjacent_string_literals :: proc(cpp: ^Preprocessor, initial_tok: ^Token) {
|
|||||||
|
|
||||||
|
|
||||||
quote_string :: proc(s: string) -> []byte {
|
quote_string :: proc(s: string) -> []byte {
|
||||||
b := strings.make_builder(0, len(s)+2)
|
b := strings.builder_make(0, len(s)+2)
|
||||||
io.write_quoted_string(strings.to_writer(&b), s, '"')
|
io.write_quoted_string(strings.to_writer(&b), s, '"')
|
||||||
return b.buf[:]
|
return b.buf[:]
|
||||||
}
|
}
|
||||||
@@ -956,7 +956,7 @@ substitute_token :: proc(cpp: ^Preprocessor, tok: ^Token, args: ^Macro_Arg) -> ^
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if tok.lit == "__VA__OPT__" && tok.next.lit == "(" {
|
if tok.lit == "__VA_OPT__" && tok.next.lit == "(" {
|
||||||
opt_arg := read_macro_arg_one(cpp, &tok, tok.next.next, true)
|
opt_arg := read_macro_arg_one(cpp, &tok, tok.next.next, true)
|
||||||
if has_varargs(args) {
|
if has_varargs(args) {
|
||||||
for t := opt_arg.tok; t.kind != .EOF; t = t.next {
|
for t := opt_arg.tok; t.kind != .EOF; t = t.next {
|
||||||
@@ -1276,7 +1276,7 @@ preprocess_internal :: proc(cpp: ^Preprocessor, tok: ^Token) -> ^Token {
|
|||||||
if start.file != nil {
|
if start.file != nil {
|
||||||
dir = filepath.dir(start.file.name)
|
dir = filepath.dir(start.file.name)
|
||||||
}
|
}
|
||||||
path := filepath.join(dir, filename)
|
path := filepath.join({dir, filename})
|
||||||
if os.exists(path) {
|
if os.exists(path) {
|
||||||
tok = include_file(cpp, tok, path, start.next.next)
|
tok = include_file(cpp, tok, path, start.next.next)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.3 Complex arithmetic
|
// 7.3 Complex arithmetic
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package libc
|
package libc
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
+18
-5
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.5 Errors
|
// 7.5 Errors
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -14,7 +14,7 @@ when ODIN_OS == "windows" {
|
|||||||
// EDOM,
|
// EDOM,
|
||||||
// EILSEQ
|
// EILSEQ
|
||||||
// ERANGE
|
// ERANGE
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@@ -27,7 +27,20 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
|||||||
ERANGE :: 34
|
ERANGE :: 34
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .OpenBSD {
|
||||||
|
@(private="file")
|
||||||
|
@(default_calling_convention="c")
|
||||||
|
foreign libc {
|
||||||
|
@(link_name="__errno")
|
||||||
|
_get_errno :: proc() -> ^int ---
|
||||||
|
}
|
||||||
|
|
||||||
|
EDOM :: 33
|
||||||
|
EILSEQ :: 84
|
||||||
|
ERANGE :: 34
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .Windows {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@@ -40,7 +53,7 @@ when ODIN_OS == "windows" {
|
|||||||
ERANGE :: 34
|
ERANGE :: 34
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
|
|||||||
+13
-13
@@ -4,9 +4,9 @@ package libc
|
|||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -211,19 +211,19 @@ _signbitf :: #force_inline proc(x: float) -> int {
|
|||||||
return int(transmute(uint32_t)x >> 31)
|
return int(transmute(uint32_t)x >> 31)
|
||||||
}
|
}
|
||||||
|
|
||||||
isfinite :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
isfinite :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return fpclassify(x) == FP_INFINITE
|
return fpclassify(x) == FP_INFINITE
|
||||||
}
|
}
|
||||||
|
|
||||||
isinf :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
isinf :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return fpclassify(x) > FP_INFINITE
|
return fpclassify(x) > FP_INFINITE
|
||||||
}
|
}
|
||||||
|
|
||||||
isnan :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
isnan :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return fpclassify(x) == FP_NAN
|
return fpclassify(x) == FP_NAN
|
||||||
}
|
}
|
||||||
|
|
||||||
isnormal :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
isnormal :: #force_inline proc(x: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return fpclassify(x) == FP_NORMAL
|
return fpclassify(x) == FP_NORMAL
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,27 +231,27 @@ isnormal :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
|
|||||||
// implemented as the relational comparisons, as that would produce an invalid
|
// implemented as the relational comparisons, as that would produce an invalid
|
||||||
// "sticky" state that propagates and affects maths results. These need
|
// "sticky" state that propagates and affects maths results. These need
|
||||||
// to be implemented natively in Odin assuming isunordered to prevent that.
|
// to be implemented natively in Odin assuming isunordered to prevent that.
|
||||||
isgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
isgreater :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return !isunordered(x, y) && x > y
|
return !isunordered(x, y) && x > y
|
||||||
}
|
}
|
||||||
|
|
||||||
isgreaterequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
isgreaterequal :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return !isunordered(x, y) && x >= y
|
return !isunordered(x, y) && x >= y
|
||||||
}
|
}
|
||||||
|
|
||||||
isless :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
isless :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return !isunordered(x, y) && x < y
|
return !isunordered(x, y) && x < y
|
||||||
}
|
}
|
||||||
|
|
||||||
islessequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
islessequal :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return !isunordered(x, y) && x <= y
|
return !isunordered(x, y) && x <= y
|
||||||
}
|
}
|
||||||
|
|
||||||
islessgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
islessgreater :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
return !isunordered(x, y) && x <= y
|
return !isunordered(x, y) && x <= y
|
||||||
}
|
}
|
||||||
|
|
||||||
isunordered :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
|
isunordered :: #force_inline proc(x, y: $T) -> bool where intrinsics.type_is_float(T) {
|
||||||
if isnan(x) {
|
if isnan(x) {
|
||||||
// Force evaluation of y to propagate exceptions for ordering semantics.
|
// Force evaluation of y to propagate exceptions for ordering semantics.
|
||||||
// To ensure correct semantics of IEEE 754 this cannot be compiled away.
|
// To ensure correct semantics of IEEE 754 this cannot be compiled away.
|
||||||
@@ -331,7 +331,7 @@ fmin :: proc{libc_fmin, libc_fminf}
|
|||||||
fma :: proc{libc_fma, libc_fmaf}
|
fma :: proc{libc_fma, libc_fmaf}
|
||||||
|
|
||||||
// But retain the 'f' suffix-variant functions as well so they can be used,
|
// But retain the 'f' suffix-variant functions as well so they can be used,
|
||||||
// a trick is used here where we use explicit procedrual overloading of one
|
// a trick is used here where we use explicit procedural overloading of one
|
||||||
// procedure. This is done because the foreign block is marked @(private) and
|
// procedure. This is done because the foreign block is marked @(private) and
|
||||||
// aliasing functions does not remove privateness from the entity.
|
// aliasing functions does not remove privateness from the entity.
|
||||||
acosf :: proc{libc_acosf}
|
acosf :: proc{libc_acosf}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package libc
|
|||||||
|
|
||||||
// 7.13 Nonlocal jumps
|
// 7.13 Nonlocal jumps
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
}
|
}
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.13.1 Save calling environment
|
// 7.13.1 Save calling environment
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.14 Signal handling
|
// 7.14 Signal handling
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -21,7 +21,7 @@ foreign libc {
|
|||||||
raise :: proc(sig: int) -> int ---
|
raise :: proc(sig: int) -> int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
@@ -34,7 +34,7 @@ when ODIN_OS == "windows" {
|
|||||||
SIGTERM :: 15
|
SIGTERM :: 15
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
@@ -47,7 +47,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
|||||||
SIGTERM :: 15
|
SIGTERM :: 15
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
|
|||||||
+111
-146
@@ -47,29 +47,30 @@ kill_dependency :: #force_inline proc(value: $T) -> T {
|
|||||||
|
|
||||||
// 7.17.4 Fences
|
// 7.17.4 Fences
|
||||||
atomic_thread_fence :: #force_inline proc(order: memory_order) {
|
atomic_thread_fence :: #force_inline proc(order: memory_order) {
|
||||||
switch (order) {
|
assert(order != .relaxed)
|
||||||
case .relaxed:
|
assert(order != .consume)
|
||||||
return
|
#partial switch order {
|
||||||
case .consume:
|
case .acquire: intrinsics.atomic_thread_fence(.Acquire)
|
||||||
intrinsics.atomic_fence_acq()
|
case .release: intrinsics.atomic_thread_fence(.Release)
|
||||||
case .acquire:
|
case .acq_rel: intrinsics.atomic_thread_fence(.Acq_Rel)
|
||||||
intrinsics.atomic_fence_acq()
|
case .seq_cst: intrinsics.atomic_thread_fence(.Seq_Cst)
|
||||||
case .release:
|
|
||||||
intrinsics.atomic_fence_rel()
|
|
||||||
case .acq_rel:
|
|
||||||
intrinsics.atomic_fence_acqrel()
|
|
||||||
case .seq_cst:
|
|
||||||
intrinsics.atomic_fence_acqrel()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_signal_fence :: #force_inline proc(order: memory_order) {
|
atomic_signal_fence :: #force_inline proc(order: memory_order) {
|
||||||
atomic_thread_fence(order)
|
assert(order != .relaxed)
|
||||||
|
assert(order != .consume)
|
||||||
|
#partial switch order {
|
||||||
|
case .acquire: intrinsics.atomic_signal_fence(.Acquire)
|
||||||
|
case .release: intrinsics.atomic_signal_fence(.Release)
|
||||||
|
case .acq_rel: intrinsics.atomic_signal_fence(.Acq_Rel)
|
||||||
|
case .seq_cst: intrinsics.atomic_signal_fence(.Seq_Cst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.17.5 Lock-free property
|
// 7.17.5 Lock-free property
|
||||||
atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
|
atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
|
||||||
return size_of(T) <= 8 && (intrinsics.type_is_integer(T) || intrinsics.type_is_pointer(T))
|
return intrinsics.atomic_type_is_lock_free(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.17.6 Atomic integer types
|
// 7.17.6 Atomic integer types
|
||||||
@@ -121,13 +122,10 @@ atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memo
|
|||||||
assert(order != .acquire)
|
assert(order != .acquire)
|
||||||
assert(order != .acq_rel)
|
assert(order != .acq_rel)
|
||||||
|
|
||||||
#partial switch (order) {
|
#partial switch order {
|
||||||
case .relaxed:
|
case .relaxed: intrinsics.atomic_store_explicit(object, desired, .Relaxed)
|
||||||
intrinsics.atomic_store_relaxed(object, desired)
|
case .release: intrinsics.atomic_store_explicit(object, desired, .Release)
|
||||||
case .release:
|
case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .Seq_Cst)
|
||||||
intrinsics.atomic_store_rel(object, desired)
|
|
||||||
case .seq_cst:
|
|
||||||
intrinsics.atomic_store(object, desired)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,36 +137,26 @@ atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) {
|
|||||||
assert(order != .release)
|
assert(order != .release)
|
||||||
assert(order != .acq_rel)
|
assert(order != .acq_rel)
|
||||||
|
|
||||||
#partial switch (order) {
|
#partial switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_load_explicit(object, .Relaxed)
|
||||||
return intrinsics.atomic_load_relaxed(object)
|
case .consume: return intrinsics.atomic_load_explicit(object, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_load_explicit(object, .Acquire)
|
||||||
return intrinsics.atomic_load_acq(object)
|
case .seq_cst: return intrinsics.atomic_load_explicit(object, .Seq_Cst)
|
||||||
case .acquire:
|
|
||||||
return intrinsics.atomic_load_acq(object)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_load(object)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
|
atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
|
||||||
return intrinsics.atomic_xchg(object, desired)
|
return intrinsics.atomic_exchange(object, desired)
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
|
atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .Relaxed)
|
||||||
return intrinsics.atomic_xchg_relaxed(object, desired)
|
case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .Acquire)
|
||||||
return intrinsics.atomic_xchg_acq(object, desired)
|
case .release: return intrinsics.atomic_exchange_explicit(object, desired, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .Acq_Rel)
|
||||||
return intrinsics.atomic_xchg_acq(object, desired)
|
case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .Seq_Cst)
|
||||||
case .release:
|
|
||||||
return intrinsics.atomic_xchg_rel(object, desired)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_xchg_acqrel(object, desired)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_xchg(object, desired)
|
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -189,102 +177,104 @@ atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: m
|
|||||||
// [success = seq_cst, failure = acquire] => failacq
|
// [success = seq_cst, failure = acquire] => failacq
|
||||||
// [success = acquire, failure = relaxed] => acq_failrelaxed
|
// [success = acquire, failure = relaxed] => acq_failrelaxed
|
||||||
// [success = acq_rel, failure = relaxed] => acqrel_failrelaxed
|
// [success = acq_rel, failure = relaxed] => acqrel_failrelaxed
|
||||||
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) {
|
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
|
||||||
value, ok := intrinsics.atomic_cxchg(object, expected^, desired)
|
value, ok := intrinsics.atomic_compare_exchange_strong(object, expected^, desired)
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) {
|
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) -> bool {
|
||||||
assert(failure != .release)
|
assert(failure != .release)
|
||||||
assert(failure != .acq_rel)
|
assert(failure != .acq_rel)
|
||||||
|
|
||||||
value: T; ok: bool
|
value: T; ok: bool
|
||||||
#partial switch (failure) {
|
#partial switch failure {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
assert(success != .relaxed)
|
assert(success != .relaxed)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchg(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Seq_Cst)
|
||||||
case .release:
|
case .release:
|
||||||
value, ok := intrinsics.atomic_cxchg_rel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Release, .Seq_Cst)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchg_acqrel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
|
||||||
}
|
}
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
assert(success != .release)
|
assert(success != .release)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
value, ok := intrinsics.atomic_cxchg_relaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Relaxed, .Relaxed)
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchg_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Relaxed)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Relaxed)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchg_acqrel_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
|
||||||
}
|
}
|
||||||
case .consume:
|
case .consume:
|
||||||
fallthrough
|
assert(success == .seq_cst)
|
||||||
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Consume)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
assert(success == .seq_cst)
|
assert(success == .seq_cst)
|
||||||
value, ok := intrinsics.atomic_cxchg_failacq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
|
||||||
|
|
||||||
}
|
}
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) {
|
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
|
||||||
value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired)
|
value, ok := intrinsics.atomic_compare_exchange_weak(object, expected^, desired)
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) {
|
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) -> bool {
|
||||||
assert(failure != .release)
|
assert(failure != .release)
|
||||||
assert(failure != .acq_rel)
|
assert(failure != .acq_rel)
|
||||||
|
|
||||||
value: T; ok: bool
|
value: T; ok: bool
|
||||||
#partial switch (failure) {
|
#partial switch failure {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
assert(success != .relaxed)
|
assert(success != .relaxed)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Seq_Cst)
|
||||||
case .release:
|
case .release:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_rel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Release, .Seq_Cst)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acqrel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
|
||||||
}
|
}
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
assert(success != .release)
|
assert(success != .release)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_relaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Relaxed, .Relaxed)
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Relaxed)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Relaxed)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acqrel_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
|
||||||
}
|
}
|
||||||
case .consume:
|
case .consume:
|
||||||
fallthrough
|
assert(success == .seq_cst)
|
||||||
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Consume)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
assert(success == .seq_cst)
|
assert(success == .seq_cst)
|
||||||
value, ok := intrinsics.atomic_cxchgweak_failacq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
|
||||||
|
|
||||||
}
|
}
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
@@ -297,19 +287,14 @@ atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_add_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_add_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_add_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_add_acq(object, operand)
|
case .release: return intrinsics.atomic_add_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_add_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_add_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_add_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_add(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,19 +303,14 @@ atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_sub_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_sub_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_sub_acq(object, operand)
|
case .release: return intrinsics.atomic_sub_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_sub_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_sub_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_sub_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_sub(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,19 +319,14 @@ atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_or_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_or_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_or_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_or_acq(object, operand)
|
case .release: return intrinsics.atomic_or_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_or_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_or_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_or_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_or(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,19 +335,14 @@ atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_xor_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_xor_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_xor_acq(object, operand)
|
case .release: return intrinsics.atomic_xor_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_xor_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_xor_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_xor_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_xor(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,19 +350,14 @@ atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
return intrinsics.atomic_and(object, operand)
|
return intrinsics.atomic_and(object, operand)
|
||||||
}
|
}
|
||||||
atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_and_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_and_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_and_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_and_acq(object, operand)
|
case .release: return intrinsics.atomic_and_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_and_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_and_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_and_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_and(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+57
-7
@@ -1,8 +1,8 @@
|
|||||||
package libc
|
package libc
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -13,7 +13,7 @@ when ODIN_OS == "windows" {
|
|||||||
FILE :: struct {}
|
FILE :: struct {}
|
||||||
|
|
||||||
// MSVCRT compatible.
|
// MSVCRT compatible.
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
_IOFBF :: 0x0000
|
_IOFBF :: 0x0000
|
||||||
_IONBF :: 0x0004
|
_IONBF :: 0x0004
|
||||||
_IOLBF :: 0x0040
|
_IOLBF :: 0x0040
|
||||||
@@ -48,7 +48,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GLIBC and MUSL compatible.
|
// GLIBC and MUSL compatible.
|
||||||
when ODIN_OS == "linux" {
|
when ODIN_OS == .Linux {
|
||||||
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
||||||
|
|
||||||
_IOFBF :: 0
|
_IOFBF :: 0
|
||||||
@@ -78,7 +78,57 @@ when ODIN_OS == "linux" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .OpenBSD {
|
||||||
|
fpos_t :: distinct i64
|
||||||
|
|
||||||
|
_IOFBF :: 0
|
||||||
|
_IOLBF :: 1
|
||||||
|
_IONBF :: 1
|
||||||
|
|
||||||
|
BUFSIZ :: 1024
|
||||||
|
|
||||||
|
EOF :: int(-1)
|
||||||
|
|
||||||
|
FOPEN_MAX :: 20
|
||||||
|
FILENAME_MAX :: 1024
|
||||||
|
|
||||||
|
SEEK_SET :: 0
|
||||||
|
SEEK_CUR :: 1
|
||||||
|
SEEK_END :: 2
|
||||||
|
|
||||||
|
foreign libc {
|
||||||
|
stderr: ^FILE
|
||||||
|
stdin: ^FILE
|
||||||
|
stdout: ^FILE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .FreeBSD {
|
||||||
|
fpos_t :: distinct i64
|
||||||
|
|
||||||
|
_IOFBF :: 0
|
||||||
|
_IOLBF :: 1
|
||||||
|
_IONBF :: 1
|
||||||
|
|
||||||
|
BUFSIZ :: 1024
|
||||||
|
|
||||||
|
EOF :: int(-1)
|
||||||
|
|
||||||
|
FOPEN_MAX :: 20
|
||||||
|
FILENAME_MAX :: 1024
|
||||||
|
|
||||||
|
SEEK_SET :: 0
|
||||||
|
SEEK_CUR :: 1
|
||||||
|
SEEK_END :: 2
|
||||||
|
|
||||||
|
foreign libc {
|
||||||
|
stderr: ^FILE
|
||||||
|
stdin: ^FILE
|
||||||
|
stdout: ^FILE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .Darwin {
|
||||||
fpos_t :: distinct i64
|
fpos_t :: distinct i64
|
||||||
|
|
||||||
_IOFBF :: 0
|
_IOFBF :: 0
|
||||||
@@ -146,10 +196,10 @@ foreign libc {
|
|||||||
getc :: proc(stream: ^FILE) -> int ---
|
getc :: proc(stream: ^FILE) -> int ---
|
||||||
getchar :: proc() -> int ---
|
getchar :: proc() -> int ---
|
||||||
putc :: proc(c: int, stream: ^FILE) -> int ---
|
putc :: proc(c: int, stream: ^FILE) -> int ---
|
||||||
putchar :: proc() -> int ---
|
putchar :: proc(c: int) -> int ---
|
||||||
puts :: proc(s: cstring) -> int ---
|
puts :: proc(s: cstring) -> int ---
|
||||||
ungetc :: proc(c: int, stream: ^FILE) -> int ---
|
ungetc :: proc(c: int, stream: ^FILE) -> int ---
|
||||||
fread :: proc(ptr: rawptr, size: size_t, stream: ^FILE) -> size_t ---
|
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||||
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||||
|
|
||||||
// 7.21.9 File positioning functions
|
// 7.21.9 File positioning functions
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ package libc
|
|||||||
|
|
||||||
// 7.22 General utilities
|
// 7.22 General utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
RAND_MAX :: 0x7fff
|
RAND_MAX :: 0x7fff
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@@ -24,7 +24,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "linux" {
|
when ODIN_OS == .Linux {
|
||||||
RAND_MAX :: 0x7fffffff
|
RAND_MAX :: 0x7fffffff
|
||||||
|
|
||||||
// GLIBC and MUSL only
|
// GLIBC and MUSL only
|
||||||
@@ -40,7 +40,7 @@ when ODIN_OS == "linux" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
RAND_MAX :: 0x7fffffff
|
RAND_MAX :: 0x7fffffff
|
||||||
|
|
||||||
// GLIBC and MUSL only
|
// GLIBC and MUSL only
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import "core:runtime"
|
|||||||
|
|
||||||
// 7.24 String handling
|
// 7.24 String handling
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ package libc
|
|||||||
thrd_start_t :: proc "c" (rawptr) -> int
|
thrd_start_t :: proc "c" (rawptr) -> int
|
||||||
tss_dtor_t :: proc "c" (rawptr)
|
tss_dtor_t :: proc "c" (rawptr)
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc {
|
foreign import libc {
|
||||||
"system:libucrt.lib",
|
"system:libucrt.lib",
|
||||||
"system:msvcprt.lib"
|
"system:msvcprt.lib",
|
||||||
}
|
}
|
||||||
|
|
||||||
thrd_success :: 0 // _Thrd_success
|
thrd_success :: 0 // _Thrd_success
|
||||||
@@ -74,10 +74,10 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GLIBC and MUSL compatible constants and types.
|
// GLIBC and MUSL compatible constants and types.
|
||||||
when ODIN_OS == "linux" {
|
when ODIN_OS == .Linux {
|
||||||
foreign import libc {
|
foreign import libc {
|
||||||
"system:c",
|
"system:c",
|
||||||
"system:pthread"
|
"system:pthread",
|
||||||
}
|
}
|
||||||
|
|
||||||
thrd_success :: 0
|
thrd_success :: 0
|
||||||
@@ -138,6 +138,6 @@ when ODIN_OS == "linux" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
// TODO: find out what this is meant to be!
|
// TODO: find out what this is meant to be!
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.27 Date and time
|
// 7.27 Date and time
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -12,7 +12,7 @@ when ODIN_OS == "windows" {
|
|||||||
|
|
||||||
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
||||||
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.27.2 Time manipulation functions
|
// 7.27.2 Time manipulation functions
|
||||||
clock :: proc() -> clock_t ---
|
clock :: proc() -> clock_t ---
|
||||||
@@ -45,7 +45,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.27.2 Time manipulation functions
|
// 7.27.2 Time manipulation functions
|
||||||
@@ -63,7 +63,12 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
|||||||
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
||||||
}
|
}
|
||||||
|
|
||||||
CLOCKS_PER_SEC :: 1000000
|
when ODIN_OS == .OpenBSD {
|
||||||
|
CLOCKS_PER_SEC :: 100
|
||||||
|
} else {
|
||||||
|
CLOCKS_PER_SEC :: 1000000
|
||||||
|
}
|
||||||
|
|
||||||
TIME_UTC :: 1
|
TIME_UTC :: 1
|
||||||
|
|
||||||
time_t :: distinct i64
|
time_t :: distinct i64
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package libc
|
|||||||
import "core:c"
|
import "core:c"
|
||||||
|
|
||||||
char :: c.char // assuming -funsigned-char
|
char :: c.char // assuming -funsigned-char
|
||||||
|
|
||||||
|
schar :: c.schar
|
||||||
short :: c.short
|
short :: c.short
|
||||||
int :: c.int
|
int :: c.int
|
||||||
long :: c.long
|
long :: c.long
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.28 Unicode utilities
|
// 7.28 Unicode utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.29 Extended multibyte and wide character utilities
|
// 7.29 Extended multibyte and wide character utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
+14
-7
@@ -2,27 +2,34 @@ package libc
|
|||||||
|
|
||||||
// 7.30 Wide character classification and mapping utilities
|
// 7.30 Wide character classification and mapping utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
wctrans_t :: distinct wchar_t
|
wctrans_t :: distinct wchar_t
|
||||||
wctype_t :: distinct ushort
|
wctype_t :: distinct ushort
|
||||||
}
|
|
||||||
|
|
||||||
when ODIN_OS == "linux" {
|
} else when ODIN_OS == .Linux {
|
||||||
wctrans_t :: distinct intptr_t
|
wctrans_t :: distinct intptr_t
|
||||||
wctype_t :: distinct ulong
|
wctype_t :: distinct ulong
|
||||||
}
|
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
wctrans_t :: distinct int
|
wctrans_t :: distinct int
|
||||||
wctype_t :: distinct u32
|
wctype_t :: distinct u32
|
||||||
|
|
||||||
|
} else when ODIN_OS == .OpenBSD {
|
||||||
|
wctrans_t :: distinct rawptr
|
||||||
|
wctype_t :: distinct rawptr
|
||||||
|
|
||||||
|
} else when ODIN_OS == .FreeBSD {
|
||||||
|
wctrans_t :: distinct int
|
||||||
|
wctype_t :: distinct ulong
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
List of contributors:
|
List of contributors:
|
||||||
Jeroen van Rijn: Initial implementation, optimization.
|
Jeroen van Rijn: Initial implementation, optimization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// package compress is a collection of utilities to aid with other compression packages
|
||||||
package compress
|
package compress
|
||||||
|
|
||||||
import "core:io"
|
import "core:io"
|
||||||
@@ -44,7 +47,7 @@ when size_of(uintptr) == 8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Error :: union {
|
Error :: union #shared_nil {
|
||||||
General_Error,
|
General_Error,
|
||||||
Deflate_Error,
|
Deflate_Error,
|
||||||
ZLIB_Error,
|
ZLIB_Error,
|
||||||
@@ -55,6 +58,7 @@ Error :: union {
|
|||||||
}
|
}
|
||||||
|
|
||||||
General_Error :: enum {
|
General_Error :: enum {
|
||||||
|
None = 0,
|
||||||
File_Not_Found,
|
File_Not_Found,
|
||||||
Cannot_Open_File,
|
Cannot_Open_File,
|
||||||
File_Too_Short,
|
File_Too_Short,
|
||||||
@@ -73,6 +77,7 @@ General_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GZIP_Error :: enum {
|
GZIP_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Invalid_GZIP_Signature,
|
Invalid_GZIP_Signature,
|
||||||
Reserved_Flag_Set,
|
Reserved_Flag_Set,
|
||||||
Invalid_Extra_Data,
|
Invalid_Extra_Data,
|
||||||
@@ -97,6 +102,7 @@ GZIP_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZIP_Error :: enum {
|
ZIP_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Invalid_ZIP_File_Signature,
|
Invalid_ZIP_File_Signature,
|
||||||
Unexpected_Signature,
|
Unexpected_Signature,
|
||||||
Insert_Next_Disk,
|
Insert_Next_Disk,
|
||||||
@@ -104,6 +110,7 @@ ZIP_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZLIB_Error :: enum {
|
ZLIB_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Unsupported_Window_Size,
|
Unsupported_Window_Size,
|
||||||
FDICT_Unsupported,
|
FDICT_Unsupported,
|
||||||
Unsupported_Compression_Level,
|
Unsupported_Compression_Level,
|
||||||
@@ -111,6 +118,7 @@ ZLIB_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Deflate_Error :: enum {
|
Deflate_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Huffman_Bad_Sizes,
|
Huffman_Bad_Sizes,
|
||||||
Huffman_Bad_Code_Lengths,
|
Huffman_Bad_Code_Lengths,
|
||||||
Inflate_Error,
|
Inflate_Error,
|
||||||
@@ -120,7 +128,6 @@ Deflate_Error :: enum {
|
|||||||
BType_3,
|
BType_3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// General I/O context for ZLIB, LZW, etc.
|
// General I/O context for ZLIB, LZW, etc.
|
||||||
Context_Memory_Input :: struct #packed {
|
Context_Memory_Input :: struct #packed {
|
||||||
input_data: []u8,
|
input_data: []u8,
|
||||||
@@ -136,7 +143,12 @@ Context_Memory_Input :: struct #packed {
|
|||||||
size_packed: i64,
|
size_packed: i64,
|
||||||
size_unpacked: i64,
|
size_unpacked: i64,
|
||||||
}
|
}
|
||||||
#assert(size_of(Context_Memory_Input) == 64)
|
when size_of(rawptr) == 8 {
|
||||||
|
#assert(size_of(Context_Memory_Input) == 64)
|
||||||
|
} else {
|
||||||
|
// e.g. `-target:windows_i386`
|
||||||
|
#assert(size_of(Context_Memory_Input) == 52)
|
||||||
|
}
|
||||||
|
|
||||||
Context_Stream_Input :: struct #packed {
|
Context_Stream_Input :: struct #packed {
|
||||||
input_data: []u8,
|
input_data: []u8,
|
||||||
@@ -171,8 +183,6 @@ Context_Stream_Input :: struct #packed {
|
|||||||
This simplifies end-of-stream handling where bits may be left in the bit buffer.
|
This simplifies end-of-stream handling where bits may be left in the bit buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: Make these return compress.Error errors.
|
|
||||||
|
|
||||||
input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Error) {
|
input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Error) {
|
||||||
return i64(len(z.input_data)), nil
|
return i64(len(z.input_data)), nil
|
||||||
}
|
}
|
||||||
@@ -284,6 +294,24 @@ peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(optimization_mode="speed")
|
||||||
|
peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
|
||||||
|
size :: size_of(T)
|
||||||
|
|
||||||
|
#no_bounds_check {
|
||||||
|
if len(z.input_data) >= size + offset {
|
||||||
|
buf := z.input_data[offset:][:size]
|
||||||
|
return (^T)(&buf[0])^, .None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(z.input_data) == 0 {
|
||||||
|
return T{}, .EOF
|
||||||
|
} else {
|
||||||
|
return T{}, .Short_Buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
|
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
|
||||||
size :: size_of(T)
|
size :: size_of(T)
|
||||||
@@ -311,7 +339,44 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
|||||||
return res, .None
|
return res, .None
|
||||||
}
|
}
|
||||||
|
|
||||||
peek_data :: proc{peek_data_from_memory, peek_data_from_stream}
|
@(optimization_mode="speed")
|
||||||
|
peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
|
||||||
|
size :: size_of(T)
|
||||||
|
|
||||||
|
// Get current position to return to.
|
||||||
|
cur_pos, e1 := z.input->impl_seek(0, .Current)
|
||||||
|
if e1 != .None {
|
||||||
|
return T{}, e1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to offset.
|
||||||
|
pos, e2 := z.input->impl_seek(offset, .Start)
|
||||||
|
if e2 != .None {
|
||||||
|
return T{}, e2
|
||||||
|
}
|
||||||
|
|
||||||
|
r, e3 := io.to_reader_at(z.input)
|
||||||
|
if !e3 {
|
||||||
|
return T{}, .Empty
|
||||||
|
}
|
||||||
|
when size <= 128 {
|
||||||
|
b: [size]u8
|
||||||
|
} else {
|
||||||
|
b := make([]u8, size, context.temp_allocator)
|
||||||
|
}
|
||||||
|
_, e4 := io.read_at(r, b[:], pos)
|
||||||
|
if e4 != .None {
|
||||||
|
return T{}, .Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return read head to original position.
|
||||||
|
z.input->impl_seek(cur_pos, .Start)
|
||||||
|
|
||||||
|
res = (^T)(&b[0])^
|
||||||
|
return res, .None
|
||||||
|
}
|
||||||
|
|
||||||
|
peek_data :: proc{peek_data_from_memory, peek_data_from_stream, peek_data_at_offset_from_memory, peek_data_at_offset_from_stream}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -470,4 +535,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
|
|||||||
consume_bits_lsb(z, discard)
|
consume_bits_lsb(z, discard)
|
||||||
}
|
}
|
||||||
|
|
||||||
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream};
|
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ main :: proc() {
|
|||||||
|
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
stderr("No input file specified.\n")
|
stderr("No input file specified.\n")
|
||||||
err := load(slice=TEST, buf=&buf, known_gzip_size=len(TEST))
|
err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
stdout("Displaying test vector: ")
|
stdout("Displaying test vector: ")
|
||||||
stdout(bytes.buffer_to_string(&buf))
|
stdout(bytes.buffer_to_string(&buf))
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ OS :: enum u8 {
|
|||||||
_Unknown = 14,
|
_Unknown = 14,
|
||||||
Unknown = 255,
|
Unknown = 255,
|
||||||
}
|
}
|
||||||
OS_Name :: #partial [OS]string{
|
OS_Name :: #sparse[OS]string{
|
||||||
|
._Unknown = "",
|
||||||
.FAT = "FAT",
|
.FAT = "FAT",
|
||||||
.Amiga = "Amiga",
|
.Amiga = "Amiga",
|
||||||
.VMS = "VMS/OpenVMS",
|
.VMS = "VMS/OpenVMS",
|
||||||
@@ -99,9 +100,9 @@ E_GZIP :: compress.GZIP_Error
|
|||||||
E_ZLIB :: compress.ZLIB_Error
|
E_ZLIB :: compress.ZLIB_Error
|
||||||
E_Deflate :: compress.Deflate_Error
|
E_Deflate :: compress.Deflate_Error
|
||||||
|
|
||||||
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le))
|
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
|
||||||
|
|
||||||
load :: proc{load_from_slice, load_from_file, load_from_context}
|
load :: proc{load_from_bytes, load_from_file, load_from_context}
|
||||||
|
|
||||||
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
@@ -111,16 +112,16 @@ load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_siz
|
|||||||
|
|
||||||
err = E_General.File_Not_Found
|
err = E_General.File_Not_Found
|
||||||
if ok {
|
if ok {
|
||||||
err = load_from_slice(data, buf, len(data), expected_output_size)
|
err = load_from_bytes(data, buf, len(data), expected_output_size)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
load_from_bytes :: proc(data: []byte, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||||
buf := buf
|
buf := buf
|
||||||
|
|
||||||
z := &compress.Context_Memory_Input{
|
z := &compress.Context_Memory_Input{
|
||||||
input_data = slice,
|
input_data = data,
|
||||||
output = buf,
|
output = buf,
|
||||||
}
|
}
|
||||||
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
|
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
|
||||||
@@ -135,7 +136,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
|
|||||||
|
|
||||||
z.output = buf
|
z.output = buf
|
||||||
|
|
||||||
if expected_output_size > GZIP_MAX_PAYLOAD_SIZE {
|
if i64(expected_output_size) > i64(GZIP_MAX_PAYLOAD_SIZE) {
|
||||||
return E_GZIP.Payload_Size_Exceeds_Max_Payload
|
return E_GZIP.Payload_Size_Exceeds_Max_Payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
This file was generated, so don't edit this by hand.
|
||||||
|
Transliterated from https://github.com/Ed-von-Schleck/shoco/blob/master/shoco_model.h,
|
||||||
|
which is an English word model.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package shoco is an implementation of the shoco short string compressor
|
||||||
|
package shoco
|
||||||
|
|
||||||
|
DEFAULT_MODEL :: Shoco_Model {
|
||||||
|
min_char = 39,
|
||||||
|
max_char = 122,
|
||||||
|
characters_by_id = {
|
||||||
|
'e', 'a', 'i', 'o', 't', 'h', 'n', 'r', 's', 'l', 'u', 'c', 'w', 'm', 'd', 'b', 'p', 'f', 'g', 'v', 'y', 'k', '-', 'H', 'M', 'T', '\'', 'B', 'x', 'I', 'W', 'L',
|
||||||
|
},
|
||||||
|
ids_by_character = {
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 23, 29, -1, -1, 31, 24, -1, -1, -1, -1, -1, -1, 25, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 15, 11, 14, 0, 17, 18, 5, 2, -1, 21, 9, 13, 6, 3, 16, -1, 7, 8, 4, 10, 19, 12, 28, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
},
|
||||||
|
successors_by_bigram = {
|
||||||
|
7, 4, 12, -1, 6, -1, 1, 0, 3, 5, -1, 9, -1, 8, 2, -1, 15, 14, -1, 10, 11, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1,
|
||||||
|
1, -1, 6, -1, 1, -1, 0, 3, 2, 4, 15, 11, -1, 9, 5, 10, 13, -1, 12, 8, 7, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
9, 11, -1, 4, 2, -1, 0, 8, 1, 5, -1, 6, -1, 3, 7, 15, -1, 12, 10, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, 14, 7, 5, -1, 1, 2, 8, 9, 0, 15, 6, 4, 11, -1, 12, 3, -1, 10, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
2, 4, 3, 1, 5, 0, -1, 6, 10, 9, 7, 12, 11, -1, -1, -1, -1, 13, -1, -1, 8, -1, 15, -1, -1, -1, 14, -1, -1, -1, -1, -1,
|
||||||
|
0, 1, 2, 3, 4, -1, -1, 5, 9, 10, 6, -1, -1, 8, 15, 11, -1, 14, -1, -1, 7, -1, 13, -1, -1, -1, 12, -1, -1, -1, -1, -1,
|
||||||
|
2, 8, 7, 4, 3, -1, 9, -1, 6, 11, -1, 5, -1, -1, 0, -1, -1, 14, 1, 15, 10, 12, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1,
|
||||||
|
0, 3, 1, 2, 6, -1, 9, 8, 4, 12, 13, 10, -1, 11, 7, -1, -1, 15, 14, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 6, 3, 4, 1, 2, -1, -1, 5, 10, 7, 9, 11, 12, -1, -1, 8, 14, -1, -1, 15, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 6, 2, 5, 9, -1, -1, -1, 10, 1, 8, -1, 12, 14, 4, -1, 15, 7, -1, 13, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
8, 10, 9, 15, 1, -1, 4, 0, 3, 2, -1, 6, -1, 12, 11, 13, 7, 14, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
1, 3, 6, 0, 4, 2, -1, 7, 13, 8, 9, 11, -1, -1, 15, -1, -1, -1, -1, -1, 10, 5, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
3, 0, 1, 4, -1, 2, 5, 6, 7, 8, -1, 14, -1, -1, 9, 15, -1, 12, -1, -1, -1, 10, 11, -1, -1, -1, 13, -1, -1, -1, -1, -1,
|
||||||
|
0, 1, 3, 2, 15, -1, 12, -1, 7, 14, 4, -1, -1, 9, -1, 8, 5, 10, -1, -1, 6, -1, 13, -1, -1, -1, 11, -1, -1, -1, -1, -1,
|
||||||
|
0, 3, 1, 2, -1, -1, 12, 6, 4, 9, 7, -1, -1, 14, 8, -1, -1, 15, 11, 13, 5, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 5, 7, 2, 10, 13, -1, 6, 8, 1, 3, -1, -1, 14, 15, 11, -1, -1, -1, 12, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 2, 6, 3, 7, 10, -1, 1, 9, 4, 8, -1, -1, 15, -1, 12, 5, -1, -1, -1, 11, -1, 13, -1, -1, -1, 14, -1, -1, -1, -1, -1,
|
||||||
|
1, 3, 4, 0, 7, -1, 12, 2, 11, 8, 6, 13, -1, -1, -1, -1, -1, 5, -1, -1, 10, 15, 9, -1, -1, -1, 14, -1, -1, -1, -1, -1,
|
||||||
|
1, 3, 5, 2, 13, 0, 9, 4, 7, 6, 8, -1, -1, 15, -1, 11, -1, -1, 10, -1, 14, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 2, 1, 3, -1, -1, -1, 6, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
1, 11, 4, 0, 3, -1, 13, 12, 2, 7, -1, -1, 15, 10, 5, 8, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, 6, -1, -1, -1, -1, -1,
|
||||||
|
0, 9, 2, 14, 15, 4, 1, 13, 3, 5, -1, -1, 10, -1, -1, -1, -1, 6, 12, -1, 7, -1, 8, -1, -1, -1, 11, -1, -1, -1, -1, -1,
|
||||||
|
-1, 2, 14, -1, 1, 5, 8, 7, 4, 12, -1, 6, 9, 11, 13, 3, 10, 15, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 1, 3, 2, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
4, 3, 1, 5, -1, -1, -1, 0, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
2, 8, 4, 1, -1, 0, -1, 6, -1, -1, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
12, 5, -1, -1, 1, -1, -1, 7, 0, 3, -1, 2, -1, 4, 6, -1, -1, -1, -1, 8, -1, -1, 15, -1, 13, 9, -1, -1, -1, -1, -1, 11,
|
||||||
|
1, 3, 2, 4, -1, -1, -1, 5, -1, 7, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1,
|
||||||
|
5, 3, 4, 12, 1, 6, -1, -1, -1, -1, 8, 2, -1, -1, -1, -1, 0, 9, -1, -1, 11, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, 0, -1, 1, 12, 3, -1, -1, -1, -1, 5, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, 6, -1, 10,
|
||||||
|
2, 3, 1, 4, -1, 0, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1,
|
||||||
|
5, 1, 3, 0, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 9, -1, -1, 6, -1, 7,
|
||||||
|
},
|
||||||
|
successors_reversed = {
|
||||||
|
's', 't', 'c', 'l', 'm', 'a', 'd', 'r', 'v', 'T', 'A', 'L', 'e', 'M', 'Y', '-',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'-', 't', 'a', 'b', 's', 'h', 'c', 'r', 'n', 'w', 'p', 'm', 'l', 'd', 'i', 'f',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'u', 'e', 'i', 'a', 'o', 'r', 'y', 'l', 'I', 'E', 'R', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'e', 'a', 'o', 'i', 'u', 'A', 'y', 'E', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
't', 'n', 'f', 's', '\'', 'm', 'I', 'N', 'A', 'E', 'L', 'Z', 'r', 'V', 'R', 'C',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'o', 'a', 'y', 'i', 'u', 'e', 'I', 'L', 'D', '\'', 'E', 'Y', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'r', 'i', 'y', 'a', 'e', 'o', 'u', 'Y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'h', 'o', 'e', 'E', 'i', 'u', 'r', 'w', 'a', 'H', 'y', 'R', 'Z', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'h', 'i', 'e', 'a', 'o', 'r', 'I', 'y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'n', 't', 's', 'r', 'l', 'd', 'i', 'y', 'v', 'm', 'b', 'c', 'g', 'p', 'k', 'u',
|
||||||
|
'e', 'l', 'o', 'u', 'y', 'a', 'r', 'i', 's', 'j', 't', 'b', 'v', 'h', 'm', 'd',
|
||||||
|
'o', 'e', 'h', 'a', 't', 'k', 'i', 'r', 'l', 'u', 'y', 'c', 'q', 's', '-', 'd',
|
||||||
|
'e', 'i', 'o', 'a', 's', 'y', 'r', 'u', 'd', 'l', '-', 'g', 'n', 'v', 'm', 'f',
|
||||||
|
'r', 'n', 'd', 's', 'a', 'l', 't', 'e', 'm', 'c', 'v', 'y', 'i', 'x', 'f', 'p',
|
||||||
|
'o', 'e', 'r', 'a', 'i', 'f', 'u', 't', 'l', '-', 'y', 's', 'n', 'c', '\'', 'k',
|
||||||
|
'h', 'e', 'o', 'a', 'r', 'i', 'l', 's', 'u', 'n', 'g', 'b', '-', 't', 'y', 'm',
|
||||||
|
'e', 'a', 'i', 'o', 't', 'r', 'u', 'y', 'm', 's', 'l', 'b', '\'', '-', 'f', 'd',
|
||||||
|
'n', 's', 't', 'm', 'o', 'l', 'c', 'd', 'r', 'e', 'g', 'a', 'f', 'v', 'z', 'b',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'e', 'n', 'i', 's', 'h', 'l', 'f', 'y', '-', 'a', 'w', '\'', 'g', 'r', 'o', 't',
|
||||||
|
'e', 'l', 'i', 'y', 'd', 'o', 'a', 'f', 'u', 't', 's', 'k', 'w', 'v', 'm', 'p',
|
||||||
|
'e', 'a', 'o', 'i', 'u', 'p', 'y', 's', 'b', 'm', 'f', '\'', 'n', '-', 'l', 't',
|
||||||
|
'd', 'g', 'e', 't', 'o', 'c', 's', 'i', 'a', 'n', 'y', 'l', 'k', '\'', 'f', 'v',
|
||||||
|
'u', 'n', 'r', 'f', 'm', 't', 'w', 'o', 's', 'l', 'v', 'd', 'p', 'k', 'i', 'c',
|
||||||
|
'e', 'r', 'a', 'o', 'l', 'p', 'i', 't', 'u', 's', 'h', 'y', 'b', '-', '\'', 'm',
|
||||||
|
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'e', 'i', 'o', 'a', 's', 'y', 't', 'd', 'r', 'n', 'c', 'm', 'l', 'u', 'g', 'f',
|
||||||
|
'e', 't', 'h', 'i', 'o', 's', 'a', 'u', 'p', 'c', 'l', 'w', 'm', 'k', 'f', 'y',
|
||||||
|
'h', 'o', 'e', 'i', 'a', 't', 'r', 'u', 'y', 'l', 's', 'w', 'c', 'f', '\'', '-',
|
||||||
|
'r', 't', 'l', 's', 'n', 'g', 'c', 'p', 'e', 'i', 'a', 'd', 'm', 'b', 'f', 'o',
|
||||||
|
'e', 'i', 'a', 'o', 'y', 'u', 'r', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||||
|
'a', 'i', 'h', 'e', 'o', 'n', 'r', 's', 'l', 'd', 'k', '-', 'f', '\'', 'c', 'b',
|
||||||
|
'p', 't', 'c', 'a', 'i', 'e', 'h', 'q', 'u', 'f', '-', 'y', 'o', '\x00', '\x00', '\x00',
|
||||||
|
'o', 'e', 's', 't', 'i', 'd', '\'', 'l', 'b', '-', 'm', 'a', 'r', 'n', 'p', 'w',
|
||||||
|
},
|
||||||
|
|
||||||
|
character_count = 32,
|
||||||
|
successor_count = 16,
|
||||||
|
|
||||||
|
max_successor_n = 7,
|
||||||
|
packs = {
|
||||||
|
{ 0x80000000, 1, 2, { 26, 24, 24, 24, 24, 24, 24, 24 }, { 15, 3, 0, 0, 0, 0, 0, 0 }, 0xc0, 0x80 },
|
||||||
|
{ 0xc0000000, 2, 4, { 25, 22, 19, 16, 16, 16, 16, 16 }, { 15, 7, 7, 7, 0, 0, 0, 0 }, 0xe0, 0xc0 },
|
||||||
|
{ 0xe0000000, 4, 8, { 23, 19, 15, 11, 8, 5, 2, 0 }, { 31, 15, 15, 15, 7, 7, 7, 3 }, 0xf0, 0xe0 },
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-3 license.
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
Jeroen van Rijn: Initial implementation.
|
||||||
|
|
||||||
|
An implementation of [shoco](https://github.com/Ed-von-Schleck/shoco) by Christian Schramm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package shoco is an implementation of the shoco short string compressor
|
||||||
|
package shoco
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:compress"
|
||||||
|
|
||||||
|
Shoco_Pack :: struct {
|
||||||
|
word: u32,
|
||||||
|
bytes_packed: i8,
|
||||||
|
bytes_unpacked: i8,
|
||||||
|
offsets: [8]u16,
|
||||||
|
masks: [8]i16,
|
||||||
|
header_mask: u8,
|
||||||
|
header: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
Shoco_Model :: struct {
|
||||||
|
min_char: u8,
|
||||||
|
max_char: u8,
|
||||||
|
characters_by_id: []u8,
|
||||||
|
ids_by_character: [256]i16,
|
||||||
|
successors_by_bigram: []i8,
|
||||||
|
successors_reversed: []u8,
|
||||||
|
|
||||||
|
character_count: u8,
|
||||||
|
successor_count: u8,
|
||||||
|
max_successor_n: i8,
|
||||||
|
packs: []Shoco_Pack,
|
||||||
|
}
|
||||||
|
|
||||||
|
compress_bound :: proc(uncompressed_size: int) -> (worst_case_compressed_size: int) {
|
||||||
|
// Worst case compression happens when input is non-ASCII (128-255)
|
||||||
|
// Encoded as 0x00 + the byte in question.
|
||||||
|
return uncompressed_size * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
decompress_bound :: proc(compressed_size: int, model := DEFAULT_MODEL) -> (maximum_decompressed_size: int) {
|
||||||
|
// Best case compression is 2:1
|
||||||
|
most: f64
|
||||||
|
for pack in model.packs {
|
||||||
|
val := f64(compressed_size) / f64(pack.bytes_packed) * f64(pack.bytes_unpacked)
|
||||||
|
most = max(most, val)
|
||||||
|
}
|
||||||
|
return int(most)
|
||||||
|
}
|
||||||
|
|
||||||
|
find_best_encoding :: proc(indices: []i16, n_consecutive: i8, model := DEFAULT_MODEL) -> (res: int) {
|
||||||
|
for p := len(model.packs); p > 0; p -= 1 {
|
||||||
|
pack := model.packs[p - 1]
|
||||||
|
if n_consecutive >= pack.bytes_unpacked {
|
||||||
|
have_index := true
|
||||||
|
for i := 0; i < int(pack.bytes_unpacked); i += 1 {
|
||||||
|
if indices[i] > pack.masks[i] {
|
||||||
|
have_index = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if have_index {
|
||||||
|
return p - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_model :: proc(model: Shoco_Model) -> (int, compress.Error) {
|
||||||
|
if len(model.characters_by_id) != int(model.character_count) {
|
||||||
|
return 0, .Unknown_Compression_Method
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(model.successors_by_bigram) != int(model.character_count) * int(model.character_count) {
|
||||||
|
return 0, .Unknown_Compression_Method
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(model.successors_reversed) != int(model.successor_count) * int(model.max_char - model.min_char) {
|
||||||
|
return 0, .Unknown_Compression_Method
|
||||||
|
}
|
||||||
|
|
||||||
|
// Model seems legit.
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompresses into provided buffer.
|
||||||
|
decompress_slice_to_output_buffer :: proc(input: []u8, output: []u8, model := DEFAULT_MODEL) -> (size: int, err: compress.Error) {
|
||||||
|
inp, inp_end := 0, len(input)
|
||||||
|
out, out_end := 0, len(output)
|
||||||
|
|
||||||
|
validate_model(model) or_return
|
||||||
|
|
||||||
|
for inp < inp_end {
|
||||||
|
val := transmute(i8)input[inp]
|
||||||
|
mark := int(-1)
|
||||||
|
|
||||||
|
for val < 0 {
|
||||||
|
val <<= 1
|
||||||
|
mark += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if mark > len(model.packs) {
|
||||||
|
return out, .Unknown_Compression_Method
|
||||||
|
}
|
||||||
|
|
||||||
|
if mark < 0 {
|
||||||
|
if out >= out_end {
|
||||||
|
return out, .Output_Too_Short
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore the sentinel value for non-ASCII chars
|
||||||
|
if input[inp] == 0x00 {
|
||||||
|
inp += 1
|
||||||
|
if inp >= inp_end {
|
||||||
|
return out, .Stream_Too_Short
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output[out] = input[inp]
|
||||||
|
inp, out = inp + 1, out + 1
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pack := model.packs[mark]
|
||||||
|
|
||||||
|
if out + int(pack.bytes_unpacked) > out_end {
|
||||||
|
return out, .Output_Too_Short
|
||||||
|
} else if inp + int(pack.bytes_packed) > inp_end {
|
||||||
|
return out, .Stream_Too_Short
|
||||||
|
}
|
||||||
|
|
||||||
|
code := intrinsics.unaligned_load((^u32)(&input[inp]))
|
||||||
|
when ODIN_ENDIAN == .Little {
|
||||||
|
code = intrinsics.byte_swap(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpack the leading char
|
||||||
|
offset := pack.offsets[0]
|
||||||
|
mask := pack.masks[0]
|
||||||
|
|
||||||
|
last_chr := model.characters_by_id[(code >> offset) & u32(mask)]
|
||||||
|
output[out] = last_chr
|
||||||
|
|
||||||
|
// Unpack the successor chars
|
||||||
|
for i := 1; i < int(pack.bytes_unpacked); i += 1 {
|
||||||
|
offset = pack.offsets[i]
|
||||||
|
mask = pack.masks[i]
|
||||||
|
|
||||||
|
index_major := u32(last_chr - model.min_char) * u32(model.successor_count)
|
||||||
|
index_minor := (code >> offset) & u32(mask)
|
||||||
|
|
||||||
|
last_chr = model.successors_reversed[index_major + index_minor]
|
||||||
|
|
||||||
|
output[out + i] = last_chr
|
||||||
|
}
|
||||||
|
|
||||||
|
out += int(pack.bytes_unpacked)
|
||||||
|
inp += int(pack.bytes_packed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (res: string, err: compress.Error) {
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
|
if len(input) == 0 {
|
||||||
|
return "", .Stream_Too_Short
|
||||||
|
}
|
||||||
|
|
||||||
|
max_output_size := decompress_bound(len(input), model)
|
||||||
|
|
||||||
|
buf: [dynamic]u8
|
||||||
|
if !resize(&buf, max_output_size) {
|
||||||
|
return "", .Out_Of_Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
length, result := decompress_slice_to_output_buffer(input, buf[:])
|
||||||
|
resize(&buf, length)
|
||||||
|
return string(buf[:]), result
|
||||||
|
}
|
||||||
|
decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
|
||||||
|
|
||||||
|
compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (size: int, err: compress.Error) {
|
||||||
|
inp, inp_end := 0, len(input)
|
||||||
|
out, out_end := 0, len(output)
|
||||||
|
output := output
|
||||||
|
|
||||||
|
validate_model(model) or_return
|
||||||
|
|
||||||
|
indices := make([]i16, model.max_successor_n + 1)
|
||||||
|
defer delete(indices)
|
||||||
|
|
||||||
|
last_resort := false
|
||||||
|
|
||||||
|
encode: for inp < inp_end {
|
||||||
|
if last_resort {
|
||||||
|
last_resort = false
|
||||||
|
|
||||||
|
if input[inp] & 0x80 == 0x80 {
|
||||||
|
// Non-ASCII case
|
||||||
|
if out + 2 > out_end {
|
||||||
|
return out, .Output_Too_Short
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put in a sentinel byte
|
||||||
|
output[out] = 0x00
|
||||||
|
out += 1
|
||||||
|
} else {
|
||||||
|
// An ASCII byte
|
||||||
|
if out + 1 > out_end {
|
||||||
|
return out, .Output_Too_Short
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output[out] = input[inp]
|
||||||
|
out, inp = out + 1, inp + 1
|
||||||
|
} else {
|
||||||
|
// Find the longest string of known successors
|
||||||
|
indices[0] = model.ids_by_character[input[inp]]
|
||||||
|
last_chr_index := indices[0]
|
||||||
|
|
||||||
|
if last_chr_index < 0 {
|
||||||
|
last_resort = true
|
||||||
|
continue encode
|
||||||
|
}
|
||||||
|
|
||||||
|
rest := inp_end - inp
|
||||||
|
n_consecutive: i8 = 1
|
||||||
|
for ; n_consecutive <= model.max_successor_n; n_consecutive += 1 {
|
||||||
|
if inp_end > 0 && int(n_consecutive) == rest {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
current_index := model.ids_by_character[input[inp + int(n_consecutive)]]
|
||||||
|
if current_index < 0 { // '\0' is always -1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
successor_index := model.successors_by_bigram[last_chr_index * i16(model.character_count) + current_index]
|
||||||
|
if successor_index < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
indices[n_consecutive] = i16(successor_index)
|
||||||
|
last_chr_index = current_index
|
||||||
|
}
|
||||||
|
|
||||||
|
if n_consecutive < 2 {
|
||||||
|
last_resort = true
|
||||||
|
continue encode
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_n := find_best_encoding(indices, n_consecutive)
|
||||||
|
if pack_n >= 0 {
|
||||||
|
if out + int(model.packs[pack_n].bytes_packed) > out_end {
|
||||||
|
return out, .Output_Too_Short
|
||||||
|
}
|
||||||
|
|
||||||
|
pack := model.packs[pack_n]
|
||||||
|
code := pack.word
|
||||||
|
|
||||||
|
for i := 0; i < int(pack.bytes_unpacked); i += 1 {
|
||||||
|
code |= u32(indices[i]) << pack.offsets[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the little-endian world, we need to swap what's in the register to match the memory representation.
|
||||||
|
when ODIN_ENDIAN == .Little {
|
||||||
|
code = intrinsics.byte_swap(code)
|
||||||
|
}
|
||||||
|
out_ptr := raw_data(output[out:])
|
||||||
|
|
||||||
|
switch pack.bytes_packed {
|
||||||
|
case 4:
|
||||||
|
intrinsics.unaligned_store(transmute(^u32)out_ptr, code)
|
||||||
|
case 2:
|
||||||
|
intrinsics.unaligned_store(transmute(^u16)out_ptr, u16(code))
|
||||||
|
case 1:
|
||||||
|
intrinsics.unaligned_store(transmute(^u8)out_ptr, u8(code))
|
||||||
|
case:
|
||||||
|
return out, .Unknown_Compression_Method
|
||||||
|
}
|
||||||
|
|
||||||
|
out += int(pack.bytes_packed)
|
||||||
|
inp += int(pack.bytes_unpacked)
|
||||||
|
} else {
|
||||||
|
last_resort = true
|
||||||
|
continue encode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := context.allocator) -> (output: []u8, err: compress.Error) {
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
|
if len(input) == 0 {
|
||||||
|
return {}, .Stream_Too_Short
|
||||||
|
}
|
||||||
|
|
||||||
|
max_output_size := compress_bound(len(input))
|
||||||
|
|
||||||
|
buf: [dynamic]u8
|
||||||
|
if !resize(&buf, max_output_size) {
|
||||||
|
return {}, .Out_Of_Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
length, result := compress_string_to_buffer(input, buf[:])
|
||||||
|
resize(&buf, length)
|
||||||
|
return buf[:length], result
|
||||||
|
}
|
||||||
|
compress :: proc{compress_string_to_buffer, compress_string}
|
||||||
@@ -47,10 +47,10 @@ Options :: struct {
|
|||||||
level: u8,
|
level: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
Error :: compress.Error
|
Error :: compress.Error
|
||||||
E_General :: compress.General_Error
|
General_Error :: compress.General_Error
|
||||||
E_ZLIB :: compress.ZLIB_Error
|
ZLIB_Error :: compress.ZLIB_Error
|
||||||
E_Deflate :: compress.Deflate_Error
|
Deflate_Error :: compress.Deflate_Error
|
||||||
|
|
||||||
DEFLATE_MAX_CHUNK_SIZE :: 65535
|
DEFLATE_MAX_CHUNK_SIZE :: 65535
|
||||||
DEFLATE_MAX_LITERAL_SIZE :: 65535
|
DEFLATE_MAX_LITERAL_SIZE :: 65535
|
||||||
@@ -111,9 +111,9 @@ ZFAST_MASK :: ((1 << ZFAST_BITS) - 1)
|
|||||||
*/
|
*/
|
||||||
Huffman_Table :: struct {
|
Huffman_Table :: struct {
|
||||||
fast: [1 << ZFAST_BITS]u16,
|
fast: [1 << ZFAST_BITS]u16,
|
||||||
firstcode: [16]u16,
|
firstcode: [17]u16,
|
||||||
maxcode: [17]int,
|
maxcode: [17]int,
|
||||||
firstsymbol: [16]u16,
|
firstsymbol: [17]u16,
|
||||||
size: [288]u8,
|
size: [288]u8,
|
||||||
value: [288]u16,
|
value: [288]u16,
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@ allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_T
|
|||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||||
sizes: [HUFFMAN_MAX_BITS+1]int
|
sizes: [HUFFMAN_MAX_BITS+1]int
|
||||||
next_code: [HUFFMAN_MAX_BITS]int
|
next_code: [HUFFMAN_MAX_BITS+1]int
|
||||||
|
|
||||||
k := int(0)
|
k := int(0)
|
||||||
|
|
||||||
@@ -256,21 +256,21 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
|||||||
}
|
}
|
||||||
sizes[0] = 0
|
sizes[0] = 0
|
||||||
|
|
||||||
for i in 1..<(HUFFMAN_MAX_BITS+1) {
|
for i in 1 ..< HUFFMAN_MAX_BITS {
|
||||||
if sizes[i] > (1 << uint(i)) {
|
if sizes[i] > (1 << uint(i)) {
|
||||||
return E_Deflate.Huffman_Bad_Sizes
|
return .Huffman_Bad_Sizes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code := int(0)
|
code := int(0)
|
||||||
|
|
||||||
for i in 1..<HUFFMAN_MAX_BITS {
|
for i in 1 ..= HUFFMAN_MAX_BITS {
|
||||||
next_code[i] = code
|
next_code[i] = code
|
||||||
z.firstcode[i] = u16(code)
|
z.firstcode[i] = u16(code)
|
||||||
z.firstsymbol[i] = u16(k)
|
z.firstsymbol[i] = u16(k)
|
||||||
code = code + sizes[i]
|
code = code + sizes[i]
|
||||||
if sizes[i] != 0 {
|
if sizes[i] != 0 {
|
||||||
if code - 1 >= (1 << u16(i)) {
|
if code - 1 >= (1 << u16(i)) {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
|
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
|
||||||
@@ -314,15 +314,15 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
|||||||
s += 1
|
s += 1
|
||||||
}
|
}
|
||||||
if s >= 16 {
|
if s >= 16 {
|
||||||
return 0, E_Deflate.Bad_Huffman_Code
|
return 0, .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
// code size is s, so:
|
// code size is s, so:
|
||||||
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
|
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
|
||||||
if b >= size_of(t.size) {
|
if b >= size_of(t.size) {
|
||||||
return 0, E_Deflate.Bad_Huffman_Code
|
return 0, .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
if t.size[b] != s {
|
if t.size[b] != s {
|
||||||
return 0, E_Deflate.Bad_Huffman_Code
|
return 0, .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
|
|
||||||
compress.consume_bits_lsb(z, s)
|
compress.consume_bits_lsb(z, s)
|
||||||
@@ -335,11 +335,11 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
|||||||
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
|
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
|
||||||
if z.num_bits < 16 {
|
if z.num_bits < 16 {
|
||||||
if z.num_bits > 63 {
|
if z.num_bits > 63 {
|
||||||
return 0, E_ZLIB.Code_Buffer_Malformed
|
return 0, .Code_Buffer_Malformed
|
||||||
}
|
}
|
||||||
compress.refill_lsb(z)
|
compress.refill_lsb(z)
|
||||||
if z.num_bits > 63 {
|
if z.num_bits > 63 {
|
||||||
return 0, E_General.Stream_Too_Short
|
return 0, .Stream_Too_Short
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
|
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
|
||||||
@@ -361,7 +361,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
if value < 256 {
|
if value < 256 {
|
||||||
e := write_byte(z, u8(value))
|
e := write_byte(z, u8(value))
|
||||||
if e != .None {
|
if e != .None {
|
||||||
return E_General.Output_Too_Short
|
return .Output_Too_Short
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if value == 256 {
|
if value == 256 {
|
||||||
@@ -377,7 +377,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
|
|
||||||
value, e = decode_huffman(z, z_offset)
|
value, e = decode_huffman(z, z_offset)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return E_Deflate.Bad_Huffman_Code
|
return .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
|
|
||||||
distance := Z_DIST_BASE[value]
|
distance := Z_DIST_BASE[value]
|
||||||
@@ -387,7 +387,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
|
|
||||||
if z.bytes_written < i64(distance) {
|
if z.bytes_written < i64(distance) {
|
||||||
// Distance is longer than we've decoded so far.
|
// Distance is longer than we've decoded so far.
|
||||||
return E_Deflate.Bad_Distance
|
return .Bad_Distance
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -405,14 +405,14 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
c := z.output.buf[z.bytes_written - i64(distance)]
|
c := z.output.buf[z.bytes_written - i64(distance)]
|
||||||
e := repl_byte(z, length, c)
|
e := repl_byte(z, length, c)
|
||||||
if e != .None {
|
if e != .None {
|
||||||
return E_General.Output_Too_Short
|
return .Output_Too_Short
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
e := repl_bytes(z, length, distance)
|
e := repl_bytes(z, length, distance)
|
||||||
if e != .None {
|
if e != .None {
|
||||||
return E_General.Output_Too_Short
|
return .Output_Too_Short
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,25 +432,25 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
if !raw {
|
if !raw {
|
||||||
size, size_err := compress.input_size(ctx)
|
size, size_err := compress.input_size(ctx)
|
||||||
if size < 6 || size_err != nil {
|
if size < 6 || size_err != nil {
|
||||||
return E_General.Stream_Too_Short
|
return .Stream_Too_Short
|
||||||
}
|
}
|
||||||
|
|
||||||
cmf, _ := compress.read_u8(ctx)
|
cmf, _ := compress.read_u8(ctx)
|
||||||
|
|
||||||
method := Compression_Method(cmf & 0xf)
|
method := Compression_Method(cmf & 0xf)
|
||||||
if method != .DEFLATE {
|
if method != .DEFLATE {
|
||||||
return E_General.Unknown_Compression_Method
|
return .Unknown_Compression_Method
|
||||||
}
|
}
|
||||||
|
|
||||||
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
|
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
|
||||||
return E_ZLIB.Unsupported_Window_Size
|
return .Unsupported_Window_Size
|
||||||
}
|
}
|
||||||
flg, _ := compress.read_u8(ctx)
|
flg, _ := compress.read_u8(ctx)
|
||||||
|
|
||||||
fcheck := flg & 0x1f
|
fcheck := flg & 0x1f
|
||||||
fcheck_computed := (cmf << 8 | flg) & 0x1f
|
fcheck_computed := (cmf << 8 | flg) & 0x1f
|
||||||
if fcheck != fcheck_computed {
|
if fcheck != fcheck_computed {
|
||||||
return E_General.Checksum_Failed
|
return .Checksum_Failed
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -458,7 +458,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
They're application specific and PNG doesn't use them.
|
They're application specific and PNG doesn't use them.
|
||||||
*/
|
*/
|
||||||
if fdict := (flg >> 5) & 1; fdict != 0 {
|
if fdict := (flg >> 5) & 1; fdict != 0 {
|
||||||
return E_ZLIB.FDICT_Unsupported
|
return .FDICT_Unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// flevel := Compression_Level((flg >> 6) & 3);
|
// flevel := Compression_Level((flg >> 6) & 3);
|
||||||
@@ -485,7 +485,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
output_hash := hash.adler32(ctx.output.buf[:])
|
output_hash := hash.adler32(ctx.output.buf[:])
|
||||||
|
|
||||||
if output_hash != u32(adler) {
|
if output_hash != u32(adler) {
|
||||||
return E_General.Checksum_Failed
|
return .Checksum_Failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -538,23 +538,24 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
final = compress.read_bits_lsb(z, 1)
|
final = compress.read_bits_lsb(z, 1)
|
||||||
type = compress.read_bits_lsb(z, 2)
|
type = compress.read_bits_lsb(z, 2)
|
||||||
|
|
||||||
// fmt.printf("Final: %v | Type: %v\n", final, type);
|
// fmt.printf("Final: %v | Type: %v\n", final, type)
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case 0:
|
case 0:
|
||||||
|
// fmt.printf("Method 0: STORED\n")
|
||||||
// Uncompressed block
|
// Uncompressed block
|
||||||
|
|
||||||
// Discard bits until next byte boundary
|
// Discard bits until next byte boundary
|
||||||
compress.discard_to_next_byte_lsb(z)
|
compress.discard_to_next_byte_lsb(z)
|
||||||
|
|
||||||
uncompressed_len := i16(compress.read_bits_lsb(z, 16))
|
uncompressed_len := u16(compress.read_bits_lsb(z, 16))
|
||||||
length_check := i16(compress.read_bits_lsb(z, 16))
|
length_check := u16(compress.read_bits_lsb(z, 16))
|
||||||
|
|
||||||
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
|
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check)
|
||||||
|
|
||||||
|
|
||||||
if ~uncompressed_len != length_check {
|
if ~uncompressed_len != length_check {
|
||||||
return E_Deflate.Len_Nlen_Mismatch
|
return .Len_Nlen_Mismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -567,10 +568,12 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
write_byte(z, u8(lit))
|
write_byte(z, u8(lit))
|
||||||
uncompressed_len -= 1
|
uncompressed_len -= 1
|
||||||
}
|
}
|
||||||
|
assert(uncompressed_len == 0)
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return E_Deflate.BType_3
|
return .BType_3
|
||||||
case:
|
case:
|
||||||
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
|
// fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type)
|
||||||
if type == 1 {
|
if type == 1 {
|
||||||
// Use fixed code lengths.
|
// Use fixed code lengths.
|
||||||
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return
|
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return
|
||||||
@@ -601,7 +604,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
c = decode_huffman(z, codelength_ht) or_return
|
c = decode_huffman(z, codelength_ht) or_return
|
||||||
|
|
||||||
if c < 0 || c >= 19 {
|
if c < 0 || c >= 19 {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
if c < 16 {
|
if c < 16 {
|
||||||
lencodes[n] = u8(c)
|
lencodes[n] = u8(c)
|
||||||
@@ -613,7 +616,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
case 16:
|
case 16:
|
||||||
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
|
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
fill = lencodes[n - 1]
|
fill = lencodes[n - 1]
|
||||||
case 17:
|
case 17:
|
||||||
@@ -621,11 +624,11 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
case 18:
|
case 18:
|
||||||
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
|
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
|
||||||
case:
|
case:
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
if ntot - n < u32(c) {
|
if ntot - n < u32(c) {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
nc := n + u32(c)
|
nc := n + u32(c)
|
||||||
@@ -636,7 +639,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n != ntot {
|
if n != ntot {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
build_huffman(z_repeat, lencodes[:hlit]) or_return
|
build_huffman(z_repeat, lencodes[:hlit]) or_return
|
||||||
@@ -674,4 +677,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
|
|||||||
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
inflate :: proc{inflate_from_context, inflate_from_byte_array};
|
inflate :: proc{inflate_from_context, inflate_from_byte_array}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package dynamic_bit_array
|
package dynamic_bit_array
|
||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note that these constants are dependent on the backing being a u64.
|
Note that these constants are dependent on the backing being a u64.
|
||||||
@@ -11,11 +12,120 @@ INDEX_SHIFT :: 6
|
|||||||
@(private="file")
|
@(private="file")
|
||||||
INDEX_MASK :: 63
|
INDEX_MASK :: 63
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
NUM_BITS :: 64
|
||||||
|
|
||||||
Bit_Array :: struct {
|
Bit_Array :: struct {
|
||||||
bits: [dynamic]u64,
|
bits: [dynamic]u64,
|
||||||
bias: int,
|
bias: int,
|
||||||
|
max_index: int,
|
||||||
|
free_pointer: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bit_Array_Iterator :: struct {
|
||||||
|
array: ^Bit_Array,
|
||||||
|
word_idx: int,
|
||||||
|
bit_idx: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- ba: ^Bit_Array - the array to iterate over
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator that holds iteration state
|
||||||
|
*/
|
||||||
|
make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
|
||||||
|
return Bit_Array_Iterator { array = ba }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- set: bool - the state of the bit at `index`
|
||||||
|
- index: int - the next bit of the Bit_Array referenced by `it`.
|
||||||
|
- ok: bool - `true` if the iterator returned a valid index,
|
||||||
|
`false` if there were no more bits
|
||||||
|
*/
|
||||||
|
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
|
||||||
|
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||||
|
if index > it.array.max_index { return false, 0, false }
|
||||||
|
|
||||||
|
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||||
|
set = (word >> it.bit_idx & 1) == 1
|
||||||
|
|
||||||
|
it.bit_idx += 1
|
||||||
|
if it.bit_idx >= NUM_BITS {
|
||||||
|
it.bit_idx = 0
|
||||||
|
it.word_idx += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return set, index, true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- index: int - the next set bit of the Bit_Array referenced by `it`.
|
||||||
|
- ok: bool - `true` if the iterator returned a valid index,
|
||||||
|
`false` if there were no more bits set
|
||||||
|
*/
|
||||||
|
iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||||
|
return iterate_internal_(it, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- index: int - the next unset bit of the Bit_Array referenced by `it`.
|
||||||
|
- ok: bool - `true` if the iterator returned a valid index,
|
||||||
|
`false` if there were no more unset bits
|
||||||
|
*/
|
||||||
|
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||||
|
return iterate_internal_(it, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
|
||||||
|
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||||
|
when ! ITERATE_SET_BITS { word = ~word }
|
||||||
|
|
||||||
|
// if the word is empty or we have already gone over all the bits in it,
|
||||||
|
// b.bit_idx is greater than the index of any set bit in the word,
|
||||||
|
// meaning that word >> b.bit_idx == 0.
|
||||||
|
for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
|
||||||
|
it.word_idx += 1
|
||||||
|
it.bit_idx = 0
|
||||||
|
word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||||
|
when ! ITERATE_SET_BITS { word = ~word }
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are iterating the set bits, reaching the end of the array means we have no more bits to check
|
||||||
|
when ITERATE_SET_BITS {
|
||||||
|
if it.word_idx >= len(it.array.bits) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reaching here means that the word has some set bits
|
||||||
|
it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
|
||||||
|
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||||
|
|
||||||
|
it.bit_idx += 1
|
||||||
|
if it.bit_idx >= NUM_BITS {
|
||||||
|
it.bit_idx = 0
|
||||||
|
it.word_idx += 1
|
||||||
|
}
|
||||||
|
return index, index <= it.array.max_index
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In:
|
In:
|
||||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||||
@@ -70,14 +180,42 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
|||||||
|
|
||||||
resize_if_needed(ba, leg_index) or_return
|
resize_if_needed(ba, leg_index) or_return
|
||||||
|
|
||||||
|
ba.max_index = max(idx, ba.max_index)
|
||||||
ba.bits[leg_index] |= 1 << uint(bit_index)
|
ba.bits[leg_index] |= 1 << uint(bit_index)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||||
|
- index: The bit index. Can be an enum member.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- ok: Whether or not we managed to unset requested bit.
|
||||||
|
|
||||||
|
`unset` automatically resizes the Bit Array to accommodate the requested index if needed.
|
||||||
|
*/
|
||||||
|
unset :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||||
|
|
||||||
|
idx := int(index) - ba.bias
|
||||||
|
|
||||||
|
if ba == nil || int(index) < ba.bias { return false }
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
|
leg_index := idx >> INDEX_SHIFT
|
||||||
|
bit_index := idx & INDEX_MASK
|
||||||
|
|
||||||
|
resize_if_needed(ba, leg_index) or_return
|
||||||
|
|
||||||
|
ba.max_index = max(idx, ba.max_index)
|
||||||
|
ba.bits[leg_index] &= ~(1 << uint(bit_index))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||||
*/
|
*/
|
||||||
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: Bit_Array, ok: bool) #optional_ok {
|
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
size_in_bits := max_index - min_index
|
size_in_bits := max_index - min_index
|
||||||
|
|
||||||
@@ -85,10 +223,11 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
|
|||||||
|
|
||||||
legs := size_in_bits >> INDEX_SHIFT
|
legs := size_in_bits >> INDEX_SHIFT
|
||||||
|
|
||||||
res = Bit_Array{
|
res = new(Bit_Array)
|
||||||
bias = min_index,
|
res.bias = min_index
|
||||||
}
|
res.max_index = max_index
|
||||||
return res, resize_if_needed(&res, size_in_bits)
|
res.free_pointer = true
|
||||||
|
return res, resize_if_needed(res, legs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -96,7 +235,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
|
|||||||
*/
|
*/
|
||||||
clear :: proc(ba: ^Bit_Array) {
|
clear :: proc(ba: ^Bit_Array) {
|
||||||
if ba == nil { return }
|
if ba == nil { return }
|
||||||
ba.bits = {}
|
mem.zero_slice(ba.bits[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -105,6 +244,9 @@ clear :: proc(ba: ^Bit_Array) {
|
|||||||
destroy :: proc(ba: ^Bit_Array) {
|
destroy :: proc(ba: ^Bit_Array) {
|
||||||
if ba == nil { return }
|
if ba == nil { return }
|
||||||
delete(ba.bits)
|
delete(ba.bits)
|
||||||
|
if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
|
||||||
|
free(ba)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -121,4 +263,4 @@ resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocat
|
|||||||
resize(&ba.bits, legs + 1)
|
resize(&ba.bits, legs + 1)
|
||||||
}
|
}
|
||||||
return len(ba.bits) > legs
|
return len(ba.bits) > legs
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package dynamic_bit_array
|
|||||||
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
|
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
|
||||||
was_set, was_retrieved := get(&bits, -1)
|
was_set, was_retrieved := get(&bits, -1)
|
||||||
fmt.println(was_set, was_retrieved)
|
fmt.println(was_set, was_retrieved)
|
||||||
|
destroy(&bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
|
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
|
||||||
@@ -40,13 +41,13 @@ package dynamic_bit_array
|
|||||||
using bit_array
|
using bit_array
|
||||||
|
|
||||||
bits := create(int(max(Foo)), int(min(Foo)))
|
bits := create(int(max(Foo)), int(min(Foo)))
|
||||||
defer destroy(&bits)
|
defer destroy(bits)
|
||||||
|
|
||||||
fmt.printf("Set(Bar): %v\n", set(&bits, Foo.Bar))
|
fmt.printf("Set(Bar): %v\n", set(bits, Foo.Bar))
|
||||||
fmt.printf("Get(Bar): %v, %v\n", get(&bits, Foo.Bar))
|
fmt.printf("Get(Bar): %v, %v\n", get(bits, Foo.Bar))
|
||||||
fmt.printf("Set(Negative_Test): %v\n", set(&bits, Foo.Negative_Test))
|
fmt.printf("Set(Negative_Test): %v\n", set(bits, Foo.Negative_Test))
|
||||||
fmt.printf("Get(Leaves): %v, %v\n", get(&bits, Foo.Leaves))
|
fmt.printf("Get(Leaves): %v, %v\n", get(bits, Foo.Leaves))
|
||||||
fmt.printf("Get(Negative_Test): %v, %v\n", get(&bits, Foo.Negative_Test))
|
fmt.printf("Get(Negative_Test): %v, %v\n", get(bits, Foo.Negative_Test))
|
||||||
fmt.printf("Freed.\n")
|
fmt.printf("Freed.\n")
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package container_intrusive_list
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
|
// An intrusive doubly-linked list
|
||||||
|
//
|
||||||
|
// As this is an intrusive container, a `Node` must be embedded in your own
|
||||||
|
// structure which is conventionally called a "link". The use of `push_front`
|
||||||
|
// and `push_back` take the address of this node. Retrieving the data
|
||||||
|
// associated with the node requires finding the relative offset of the node
|
||||||
|
// of the parent structure. The parent type and field name are given to
|
||||||
|
// `iterator_*` procedures, or to the built-in `container_of` procedure.
|
||||||
|
//
|
||||||
|
// This data structure is two-pointers in size:
|
||||||
|
// 8 bytes on 32-bit platforms and 16 bytes on 64-bit platforms
|
||||||
|
List :: struct {
|
||||||
|
head: ^Node,
|
||||||
|
tail: ^Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node :: struct {
|
||||||
|
next, prev: ^Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
push_front :: proc(list: ^List, node: ^Node) {
|
||||||
|
if list.head != nil {
|
||||||
|
list.head.prev = node
|
||||||
|
node.prev, node.next = nil, list.head
|
||||||
|
list.head = node
|
||||||
|
} else {
|
||||||
|
list.head, list.tail = node, node
|
||||||
|
node.prev, node.next = nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push_back :: proc(list: ^List, node: ^Node) {
|
||||||
|
if list.tail != nil {
|
||||||
|
list.tail.next = node
|
||||||
|
node.prev, node.next = list.tail, nil
|
||||||
|
list.tail = node
|
||||||
|
} else {
|
||||||
|
list.head, list.tail = node, node
|
||||||
|
node.prev, node.next = nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove :: proc(list: ^List, node: ^Node) {
|
||||||
|
if node != nil {
|
||||||
|
if node.next != nil {
|
||||||
|
node.next.prev = node.prev
|
||||||
|
}
|
||||||
|
if node.prev != nil {
|
||||||
|
node.prev.next = node.next
|
||||||
|
}
|
||||||
|
if list.head == node {
|
||||||
|
list.head = node.next
|
||||||
|
}
|
||||||
|
if list.tail == node {
|
||||||
|
list.tail = node.prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
|
||||||
|
for node := list.head; node != nil; {
|
||||||
|
next := node.next
|
||||||
|
if to_erase(node) {
|
||||||
|
if node.next != nil {
|
||||||
|
node.next.prev = node.prev
|
||||||
|
}
|
||||||
|
if node.prev != nil {
|
||||||
|
node.prev.next = node.next
|
||||||
|
}
|
||||||
|
if list.head == node {
|
||||||
|
list.head = node.next
|
||||||
|
}
|
||||||
|
if list.tail == node {
|
||||||
|
list.tail = node.prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
is_empty :: proc(list: ^List) -> bool {
|
||||||
|
return list.head == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pop_front :: proc(list: ^List) -> ^Node {
|
||||||
|
link := list.head
|
||||||
|
if link == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if link.next != nil {
|
||||||
|
link.next.prev = link.prev
|
||||||
|
}
|
||||||
|
if link.prev != nil {
|
||||||
|
link.prev.next = link.next
|
||||||
|
}
|
||||||
|
if link == list.head {
|
||||||
|
list.head = link.next
|
||||||
|
}
|
||||||
|
if link == list.tail {
|
||||||
|
list.tail = link.prev
|
||||||
|
}
|
||||||
|
return link
|
||||||
|
|
||||||
|
}
|
||||||
|
pop_back :: proc(list: ^List) -> ^Node {
|
||||||
|
link := list.tail
|
||||||
|
if link == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if link.next != nil {
|
||||||
|
link.next.prev = link.prev
|
||||||
|
}
|
||||||
|
if link.prev != nil {
|
||||||
|
link.prev.next = link.next
|
||||||
|
}
|
||||||
|
if link == list.head {
|
||||||
|
list.head = link.next
|
||||||
|
}
|
||||||
|
if link == list.tail {
|
||||||
|
list.tail = link.prev
|
||||||
|
}
|
||||||
|
return link
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Iterator :: struct($T: typeid) {
|
||||||
|
curr: ^Node,
|
||||||
|
offset: uintptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||||
|
where intrinsics.type_has_field(T, field_name),
|
||||||
|
intrinsics.type_field_type(T, field_name) == Node {
|
||||||
|
return {list.head, offset_of_by_string(T, field_name)}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator_tail :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||||
|
where intrinsics.type_has_field(T, field_name),
|
||||||
|
intrinsics.type_field_type(T, field_name) == Node {
|
||||||
|
return {list.tail, offset_of_by_string(T, field_name)}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator_from_node :: proc(node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
|
||||||
|
where intrinsics.type_has_field(T, field_name),
|
||||||
|
intrinsics.type_field_type(T, field_name) == Node {
|
||||||
|
return {node, offset_of_by_string(T, field_name)}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||||
|
node := it.curr
|
||||||
|
if node == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
it.curr = node.next
|
||||||
|
|
||||||
|
return (^T)(uintptr(node) - it.offset), true
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||||
|
node := it.curr
|
||||||
|
if node == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
it.curr = node.prev
|
||||||
|
|
||||||
|
return (^T)(uintptr(node) - it.offset), true
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
package container_lru
|
||||||
|
|
||||||
|
import "core:runtime"
|
||||||
|
import "core:intrinsics"
|
||||||
|
_ :: runtime
|
||||||
|
_ :: intrinsics
|
||||||
|
|
||||||
|
Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||||
|
prev, next: ^Node(Key, Value),
|
||||||
|
key: Key,
|
||||||
|
value: Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache is an LRU cache. It automatically removes entries as new entries are
|
||||||
|
// added if the capacity is reached. Entries are removed based on how recently
|
||||||
|
// they were used where the oldest entries are removed first.
|
||||||
|
Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||||
|
head: ^Node(Key, Value),
|
||||||
|
tail: ^Node(Key, Value),
|
||||||
|
|
||||||
|
entries: map[Key]^Node(Key, Value),
|
||||||
|
|
||||||
|
count: int,
|
||||||
|
capacity: int,
|
||||||
|
|
||||||
|
node_allocator: runtime.Allocator,
|
||||||
|
|
||||||
|
on_remove: proc(key: Key, value: Value, user_data: rawptr),
|
||||||
|
on_remove_user_data: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes a Cache
|
||||||
|
init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := context.allocator, node_allocator := context.allocator) {
|
||||||
|
c.entries.allocator = entries_allocator
|
||||||
|
c.node_allocator = node_allocator
|
||||||
|
c.capacity = capacity
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy deinitializes a Cachem
|
||||||
|
destroy :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
|
||||||
|
clear(c, call_on_remove)
|
||||||
|
delete(c.entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the contents of a Cache
|
||||||
|
clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
|
||||||
|
for _, node in c.entries {
|
||||||
|
if call_on_remove {
|
||||||
|
_call_on_remove(c, node)
|
||||||
|
}
|
||||||
|
free(node, c.node_allocator)
|
||||||
|
}
|
||||||
|
runtime.clear(&c.entries)
|
||||||
|
c.head = nil
|
||||||
|
c.tail = nil
|
||||||
|
c.count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the given key value pair. This operation updates the recent usage of the item.
|
||||||
|
set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error {
|
||||||
|
if e, ok := c.entries[key]; ok {
|
||||||
|
e.value = value
|
||||||
|
_pop_node(c, e)
|
||||||
|
_push_front_node(c, e)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
e : ^Node(Key, Value) = nil
|
||||||
|
assert(c.count <= c.capacity)
|
||||||
|
if c.count == c.capacity {
|
||||||
|
e = c.tail
|
||||||
|
_remove_node(c, e)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c.count += 1
|
||||||
|
e = new(Node(Key, Value), c.node_allocator) or_return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.key = key
|
||||||
|
e.value = value
|
||||||
|
_push_front_node(c, e)
|
||||||
|
c.entries[key] = e
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a value from the cache from a given key. This operation updates the usage of the item.
|
||||||
|
get :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||||
|
e: ^Node(Key, Value)
|
||||||
|
e, ok = c.entries[key]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_pop_node(c, e)
|
||||||
|
_push_front_node(c, e)
|
||||||
|
return e.value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_ptr gets the pointer to a value the cache from a given key. This operation updates the usage of the item.
|
||||||
|
get_ptr :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: ^Value, ok: bool) #optional_ok {
|
||||||
|
e: ^Node(Key, Value)
|
||||||
|
e, ok = c.entries[key]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_pop_node(c, e)
|
||||||
|
_push_front_node(c, e)
|
||||||
|
return &e.value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek gets the value from the cache from a given key without updating the recent usage.
|
||||||
|
peek :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||||
|
e: ^Node(Key, Value)
|
||||||
|
e, ok = c.entries[key]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return e.value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// exists checks for the existence of a value from a given key without updating the recent usage.
|
||||||
|
exists :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||||
|
return key in c.entries
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove removes an item from the cache.
|
||||||
|
remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||||
|
e, ok := c.entries[key]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_remove_node(c, e)
|
||||||
|
free(node, c.node_allocator)
|
||||||
|
c.count -= 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
||||||
|
if c.head == node {
|
||||||
|
c.head = node.next
|
||||||
|
}
|
||||||
|
if c.tail == node {
|
||||||
|
c.tail = node.prev
|
||||||
|
}
|
||||||
|
if node.prev != nil {
|
||||||
|
node.prev.next = node.next
|
||||||
|
}
|
||||||
|
if node.next != nil {
|
||||||
|
node.next.prev = node.prev
|
||||||
|
}
|
||||||
|
node.prev = nil
|
||||||
|
node.next = nil
|
||||||
|
|
||||||
|
delete_key(&c.entries, node.key)
|
||||||
|
|
||||||
|
_call_on_remove(c, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_call_on_remove :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
||||||
|
if c.on_remove != nil {
|
||||||
|
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||||
|
if c.head != nil {
|
||||||
|
e.next = c.head
|
||||||
|
e.next.prev = e
|
||||||
|
}
|
||||||
|
c.head = e
|
||||||
|
if c.tail == nil {
|
||||||
|
c.tail = e
|
||||||
|
}
|
||||||
|
e.prev = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||||
|
if e == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.head == e {
|
||||||
|
c.head = e.next
|
||||||
|
}
|
||||||
|
if c.tail == e {
|
||||||
|
c.tail = e.prev
|
||||||
|
}
|
||||||
|
if e.prev != nil {
|
||||||
|
e.prev.next = e.next
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.next != nil {
|
||||||
|
e.next.prev = e.prev
|
||||||
|
}
|
||||||
|
e.prev = nil
|
||||||
|
e.next = nil
|
||||||
|
}
|
||||||
@@ -85,7 +85,6 @@ _shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool {
|
|||||||
_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) {
|
_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) {
|
||||||
j := j
|
j := j
|
||||||
queue := pq.queue[:]
|
queue := pq.queue[:]
|
||||||
n := builtin.len(queue)
|
|
||||||
for 0 <= j {
|
for 0 <= j {
|
||||||
i := (j-1)/2
|
i := (j-1)/2
|
||||||
if i == j || !pq.less(queue[j], queue[i]) {
|
if i == j || !pq.less(queue[j], queue[i]) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package container_queue
|
|||||||
|
|
||||||
import "core:builtin"
|
import "core:builtin"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
_ :: runtime
|
||||||
|
|
||||||
// Dynamically resizable double-ended queue/ring-buffer
|
// Dynamically resizable double-ended queue/ring-buffer
|
||||||
Queue :: struct($T: typeid) {
|
Queue :: struct($T: typeid) {
|
||||||
@@ -68,6 +69,23 @@ get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
|
|||||||
idx := (uint(i)+q.offset)%builtin.len(q.data)
|
idx := (uint(i)+q.offset)%builtin.len(q.data)
|
||||||
return q.data[idx]
|
return q.data[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
front :: proc(q: ^$Q/Queue($T)) -> T {
|
||||||
|
return q.data[q.offset]
|
||||||
|
}
|
||||||
|
front_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
|
||||||
|
return &q.data[q.offset]
|
||||||
|
}
|
||||||
|
|
||||||
|
back :: proc(q: ^$Q/Queue($T)) -> T {
|
||||||
|
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||||
|
return q.data[idx]
|
||||||
|
}
|
||||||
|
back_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
|
||||||
|
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||||
|
return &q.data[idx]
|
||||||
|
}
|
||||||
|
|
||||||
set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
|
set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
|
||||||
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
|
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
|
||||||
|
|
||||||
@@ -81,12 +99,25 @@ get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^
|
|||||||
return &q.data[idx]
|
return &q.data[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peek_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||||
|
runtime.bounds_check_error_loc(loc, 0, builtin.len(q.data))
|
||||||
|
idx := q.offset%builtin.len(q.data)
|
||||||
|
return &q.data[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||||
|
runtime.bounds_check_error_loc(loc, int(q.len - 1), builtin.len(q.data))
|
||||||
|
idx := (uint(q.len - 1)+q.offset)%builtin.len(q.data)
|
||||||
|
return &q.data[idx]
|
||||||
|
}
|
||||||
|
|
||||||
// Push an element to the back of the queue
|
// Push an element to the back of the queue
|
||||||
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||||
if space(q^) == 0 {
|
if space(q^) == 0 {
|
||||||
_grow(q) or_return
|
_grow(q) or_return
|
||||||
}
|
}
|
||||||
q.data[q.len] = elem
|
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||||
|
q.data[idx] = elem
|
||||||
q.len += 1
|
q.len += 1
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -126,6 +157,7 @@ pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
|||||||
pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
||||||
assert(condition=q.len > 0, loc=loc)
|
assert(condition=q.len > 0, loc=loc)
|
||||||
elem = q.data[q.offset]
|
elem = q.data[q.offset]
|
||||||
|
q.offset = (q.offset+1)%builtin.len(q.data)
|
||||||
q.len -= 1
|
q.len -= 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -133,6 +165,7 @@ pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
|||||||
pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||||
if q.len > 0 {
|
if q.len > 0 {
|
||||||
elem = q.data[q.offset]
|
elem = q.data[q.offset]
|
||||||
|
q.offset = (q.offset+1)%builtin.len(q.data)
|
||||||
q.len -= 1
|
q.len -= 1
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T {
|
get :: proc(a: $A/Small_Array($N, $T), index: int) -> T {
|
||||||
return a.data[index]
|
return a.data[index]
|
||||||
}
|
}
|
||||||
get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T {
|
get_ptr :: proc(a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
||||||
return &a.data[index]
|
return &a.data[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) {
|
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||||
a.data[index] = item
|
a.data[index] = item
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (T, bool) {
|
pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||||
if N > 0 && a.len > 0 {
|
if N > 0 && a.len > 0 {
|
||||||
item = a.data[0]
|
item = a.data[0]
|
||||||
s := slice(a)
|
s := slice(a)
|
||||||
@@ -114,4 +114,4 @@ push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
|
|||||||
append_elem :: push_back
|
append_elem :: push_back
|
||||||
append_elems :: push_back_elems
|
append_elems :: push_back_elems
|
||||||
push :: proc{push_back, push_back_elems}
|
push :: proc{push_back, push_back_elems}
|
||||||
append :: proc{push_back, push_back_elems}
|
append :: proc{push_back, push_back_elems}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// The following is a generic O(V+E) topological sorter implementation.
|
||||||
|
// This is the fastest known method for topological sorting and Odin's
|
||||||
|
// map type is being used to accelerate lookups.
|
||||||
|
package container_topological_sort
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:runtime"
|
||||||
|
_ :: intrinsics
|
||||||
|
_ :: runtime
|
||||||
|
|
||||||
|
|
||||||
|
Relations :: struct($K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||||
|
dependents: map[K]bool,
|
||||||
|
dependencies: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
Sorter :: struct(K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||||
|
relations: map[K]Relations(K),
|
||||||
|
dependents_allocator: runtime.Allocator,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
make_relations :: proc(sorter: ^$S/Sorter($K)) -> (r: Relations(K)) {
|
||||||
|
r.dependents.allocator = sorter.dependents_allocator
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init :: proc(sorter: ^$S/Sorter($K)) {
|
||||||
|
sorter.relations = make(map[K]Relations(K))
|
||||||
|
sorter.dependents_allocator = context.allocator
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy :: proc(sorter: ^$S/Sorter($K)) {
|
||||||
|
for _, v in &sorter.relations {
|
||||||
|
delete(v.dependents)
|
||||||
|
}
|
||||||
|
delete(sorter.relations)
|
||||||
|
}
|
||||||
|
|
||||||
|
add_key :: proc(sorter: ^$S/Sorter($K), key: K) -> bool {
|
||||||
|
if key in sorter.relations {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sorter.relations[key] = make_relations(sorter)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool {
|
||||||
|
if key == dependency {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
find := &sorter.relations[dependency]
|
||||||
|
if find == nil {
|
||||||
|
find = map_insert(&sorter.relations, dependency, make_relations(sorter))
|
||||||
|
}
|
||||||
|
|
||||||
|
if find.dependents[key] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
find.dependents[key] = true
|
||||||
|
|
||||||
|
find = &sorter.relations[key]
|
||||||
|
if find == nil {
|
||||||
|
find = map_insert(&sorter.relations, key, make_relations(sorter))
|
||||||
|
}
|
||||||
|
|
||||||
|
find.dependencies += 1
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) {
|
||||||
|
relations := &sorter.relations
|
||||||
|
|
||||||
|
for k, v in relations {
|
||||||
|
if v.dependencies == 0 {
|
||||||
|
append(&sorted, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for root in &sorted do for k, _ in relations[root].dependents {
|
||||||
|
relation := &relations[k]
|
||||||
|
relation.dependencies -= 1
|
||||||
|
if relation.dependencies == 0 {
|
||||||
|
append(&sorted, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in relations {
|
||||||
|
if v.dependencies != 0 {
|
||||||
|
append(&cycled, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -81,7 +81,7 @@ The crypto package is not thread-safe at the moment. This may change in the futu
|
|||||||
### Disclaimer
|
### Disclaimer
|
||||||
The algorithms were ported out of curiosity and due to interest in the field.
|
The algorithms were ported out of curiosity and due to interest in the field.
|
||||||
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
|
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
|
||||||
Whereever we were able to find official test vectors, those were used to verify the implementation.
|
Wherever we were able to find official test vectors, those were used to verify the implementation.
|
||||||
We do not recommend using them in a production environment, without any additional testing and/or verification.
|
We do not recommend using them in a production environment, without any additional testing and/or verification.
|
||||||
|
|
||||||
### ToDo
|
### ToDo
|
||||||
|
|||||||
@@ -30,6 +30,6 @@ equivalence.
|
|||||||
|
|
||||||
For the most part, alterations to the base fiat-crypto generated code was
|
For the most part, alterations to the base fiat-crypto generated code was
|
||||||
kept to a minimum, to aid auditability. This results in a somewhat
|
kept to a minimum, to aid auditability. This results in a somewhat
|
||||||
ideosyncratic style, and in some cases minor performance penalties.
|
idiosyncratic style, and in some cases minor performance penalties.
|
||||||
|
|
||||||
[1]: https://github.com/mit-plv/fiat-crypto
|
[1]: https://github.com/mit-plv/fiat-crypto
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
|
|||||||
|
|
||||||
assert(len(arg1) == 16)
|
assert(len(arg1) == 16)
|
||||||
|
|
||||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||||
// While it may be unwise to do deserialization here on our
|
// While it may be unwise to do deserialization here on our
|
||||||
// own when fiat-crypto provides equivalent functionality,
|
// own when fiat-crypto provides equivalent functionality,
|
||||||
// doing it this way provides a little under 3x performance
|
// doing it this way provides a little under 3x performance
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) {
|
|||||||
t: u64 = ---
|
t: u64 = ---
|
||||||
bc: [5]u64 = ---
|
bc: [5]u64 = ---
|
||||||
|
|
||||||
when ODIN_ENDIAN != "little" {
|
when ODIN_ENDIAN != .Little {
|
||||||
v: uintptr = ---
|
v: uintptr = ---
|
||||||
for i = 0; i < 25; i += 1 {
|
for i = 0; i < 25; i += 1 {
|
||||||
v := uintptr(&st[i])
|
v := uintptr(&st[i])
|
||||||
@@ -98,7 +98,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) {
|
|||||||
st[0] ~= keccakf_rndc[r]
|
st[0] ~= keccakf_rndc[r]
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_ENDIAN != "little" {
|
when ODIN_ENDIAN != .Little {
|
||||||
for i = 0; i < 25; i += 1 {
|
for i = 0; i < 25; i += 1 {
|
||||||
v = uintptr(&st[i])
|
v = uintptr(&st[i])
|
||||||
t = st[i]
|
t = st[i]
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||||
@@ -123,7 +123,7 @@ hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -202,7 +202,7 @@ hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||||
@@ -281,7 +281,7 @@ hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
|||||||
// Until dedicated assembly can be written leverage the fact that
|
// Until dedicated assembly can be written leverage the fact that
|
||||||
// the callers of this routine ensure that src/dst are valid.
|
// the callers of this routine ensure that src/dst are valid.
|
||||||
|
|
||||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||||
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
||||||
// systems that also happen to not be strict about aligned
|
// systems that also happen to not be strict about aligned
|
||||||
// memory access.
|
// memory access.
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||||
@@ -123,7 +123,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -202,7 +202,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||||
@@ -281,7 +281,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ hash_bytes_128_3 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128_3 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128_3 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128_3 will hash the given input and write the
|
// hash_bytes_to_buffer_128_3 will hash the given input and write the
|
||||||
@@ -135,7 +135,7 @@ hash_bytes_128_4 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128_4 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128_4 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128_4 will hash the given input and write the
|
// hash_bytes_to_buffer_128_4 will hash the given input and write the
|
||||||
@@ -220,7 +220,7 @@ hash_bytes_128_5 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128_5 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128_5 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128_5 will hash the given input and write the
|
// hash_bytes_to_buffer_128_5 will hash the given input and write the
|
||||||
@@ -305,7 +305,7 @@ hash_bytes_160_3 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_160_3 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_160_3 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_160_3 will hash the given input and write the
|
// hash_bytes_to_buffer_160_3 will hash the given input and write the
|
||||||
@@ -390,7 +390,7 @@ hash_bytes_160_4 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_160_4 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_160_4 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_160_4 will hash the given input and write the
|
// hash_bytes_to_buffer_160_4 will hash the given input and write the
|
||||||
@@ -475,7 +475,7 @@ hash_bytes_160_5 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_160_5 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_160_5 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_160_5 will hash the given input and write the
|
// hash_bytes_to_buffer_160_5 will hash the given input and write the
|
||||||
@@ -560,7 +560,7 @@ hash_bytes_192_3 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_192_3 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_192_3 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_192_3 will hash the given input and write the
|
// hash_bytes_to_buffer_192_3 will hash the given input and write the
|
||||||
@@ -645,7 +645,7 @@ hash_bytes_192_4 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_192_4 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_192_4 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_192_4 will hash the given input and write the
|
// hash_bytes_to_buffer_192_4 will hash the given input and write the
|
||||||
@@ -730,7 +730,7 @@ hash_bytes_192_5 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_192_5 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_192_5 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_192_5 will hash the given input and write the
|
// hash_bytes_to_buffer_192_5 will hash the given input and write the
|
||||||
@@ -815,7 +815,7 @@ hash_bytes_224_3 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224_3 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224_3 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224_3 will hash the given input and write the
|
// hash_bytes_to_buffer_224_3 will hash the given input and write the
|
||||||
@@ -900,7 +900,7 @@ hash_bytes_224_4 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224_4 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224_4 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224_4 will hash the given input and write the
|
// hash_bytes_to_buffer_224_4 will hash the given input and write the
|
||||||
@@ -985,7 +985,7 @@ hash_bytes_224_5 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224_5 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224_5 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224_5 will hash the given input and write the
|
// hash_bytes_to_buffer_224_5 will hash the given input and write the
|
||||||
@@ -1070,7 +1070,7 @@ hash_bytes_256_3 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256_3 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256_3 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256_3 will hash the given input and write the
|
// hash_bytes_to_buffer_256_3 will hash the given input and write the
|
||||||
@@ -1155,7 +1155,7 @@ hash_bytes_256_4 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256_4 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256_4 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256_4 will hash the given input and write the
|
// hash_bytes_to_buffer_256_4 will hash the given input and write the
|
||||||
@@ -1240,7 +1240,7 @@ hash_bytes_256_5 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256_5 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256_5 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256_5 will hash the given input and write the
|
// hash_bytes_to_buffer_256_5 will hash the given input and write the
|
||||||
@@ -1332,7 +1332,7 @@ update :: proc(ctx: ^Haval_Context, data: []byte) {
|
|||||||
}
|
}
|
||||||
ctx.count[1] += str_len >> 29
|
ctx.count[1] += str_len >> 29
|
||||||
|
|
||||||
when ODIN_ENDIAN == "little" {
|
when ODIN_ENDIAN == .Little {
|
||||||
if rmd_len + str_len >= 128 {
|
if rmd_len + str_len >= 128 {
|
||||||
copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len])
|
copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len])
|
||||||
block(ctx, ctx.rounds)
|
block(ctx, ctx.rounds)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||||
@@ -123,7 +123,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -202,7 +202,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||||
@@ -281,7 +281,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||||
@@ -131,7 +131,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -213,7 +213,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||||
@@ -295,7 +295,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
when ODIN_OS != "linux" {
|
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows {
|
||||||
_rand_bytes :: proc (dst: []byte) {
|
_rand_bytes :: proc (dst: []byte) {
|
||||||
unimplemented("crypto: rand_bytes not supported on this OS")
|
unimplemented("crypto: rand_bytes not supported on this OS")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
|
||||||
|
foreign import libc "system:c"
|
||||||
|
foreign libc {
|
||||||
|
arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
|
||||||
|
}
|
||||||
|
|
||||||
|
_rand_bytes :: proc (dst: []byte) {
|
||||||
|
arc4random_buf(raw_data(dst), len(dst))
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import win32 "core:sys/windows"
|
||||||
|
import "core:os"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
_rand_bytes :: proc(dst: []byte) {
|
||||||
|
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
|
||||||
|
if ret != os.ERROR_NONE {
|
||||||
|
switch ret {
|
||||||
|
case os.ERROR_INVALID_HANDLE:
|
||||||
|
// The handle to the first parameter is invalid.
|
||||||
|
// This should not happen here, since we explicitly pass nil to it
|
||||||
|
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
|
||||||
|
case os.ERROR_INVALID_PARAMETER:
|
||||||
|
// One of the parameters was invalid
|
||||||
|
panic("crypto: BCryptGenRandom Invalid parameter")
|
||||||
|
case:
|
||||||
|
// Unknown error
|
||||||
|
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||||
@@ -121,7 +121,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||||
@@ -197,7 +197,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -273,7 +273,7 @@ hash_bytes_320 :: proc(data: []byte) -> [DIGEST_SIZE_320]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_320 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_320 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_320(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_320(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_320 will hash the given input and write the
|
// hash_bytes_to_buffer_320 will hash the given input and write the
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||||
@@ -127,7 +127,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -206,7 +206,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||||
@@ -285,7 +285,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
@@ -419,8 +419,10 @@ update :: proc(ctx: ^$T, data: []byte) {
|
|||||||
sha2_transf(ctx, shifted_message, block_nb)
|
sha2_transf(ctx, shifted_message, block_nb)
|
||||||
|
|
||||||
rem_len = new_len % CURR_BLOCK_SIZE
|
rem_len = new_len % CURR_BLOCK_SIZE
|
||||||
when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])}
|
if rem_len > 0 {
|
||||||
else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])}
|
when T == Sha256_Context {copy(ctx.block[:], shifted_message[block_nb << 6:rem_len])}
|
||||||
|
else when T == Sha512_Context {copy(ctx.block[:], shifted_message[block_nb << 7:rem_len])}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.length = rem_len
|
ctx.length = rem_len
|
||||||
when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6}
|
when T == Sha256_Context {ctx.tot_len += (block_nb + 1) << 6}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||||
@@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||||
@@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||||
@@ -128,7 +128,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
package siphash
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2022 zhibog
|
||||||
|
Made available under the BSD-3 license.
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
zhibog: Initial implementation.
|
||||||
|
|
||||||
|
Implementation of the SipHash hashing algorithm, as defined at <https://github.com/veorq/SipHash> and <https://www.aumasson.jp/siphash/siphash.pdf>
|
||||||
|
|
||||||
|
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "core:crypto"
|
||||||
|
import "core:crypto/util"
|
||||||
|
|
||||||
|
/*
|
||||||
|
High level API
|
||||||
|
*/
|
||||||
|
|
||||||
|
KEY_SIZE :: 16
|
||||||
|
DIGEST_SIZE :: 8
|
||||||
|
|
||||||
|
// sum_string_1_3 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_string_1_3 :: proc(msg, key: string) -> u64 {
|
||||||
|
return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_1_3 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 {
|
||||||
|
ctx: Context
|
||||||
|
hash: u64
|
||||||
|
init(&ctx, key, 1, 3)
|
||||||
|
update(&ctx, msg)
|
||||||
|
final(&ctx, &hash)
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_to_buffer_1_3 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) {
|
||||||
|
sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_to_buffer_1_3 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) {
|
||||||
|
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||||
|
hash := sum_bytes_1_3(msg, key)
|
||||||
|
_collect_output(dst[:], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_1_3 :: proc {
|
||||||
|
sum_string_1_3,
|
||||||
|
sum_bytes_1_3,
|
||||||
|
sum_string_to_buffer_1_3,
|
||||||
|
sum_bytes_to_buffer_1_3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_u64_1_3 will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||||
|
return sum_bytes_1_3(msg, key) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_bytes will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool {
|
||||||
|
derived_tag: [8]byte
|
||||||
|
sum_bytes_to_buffer_1_3(msg, key, derived_tag[:])
|
||||||
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_1_3 :: proc {
|
||||||
|
verify_bytes_1_3,
|
||||||
|
verify_u64_1_3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_2_4 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_string_2_4 :: proc(msg, key: string) -> u64 {
|
||||||
|
return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_2_4 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 {
|
||||||
|
ctx: Context
|
||||||
|
hash: u64
|
||||||
|
init(&ctx, key, 2, 4)
|
||||||
|
update(&ctx, msg)
|
||||||
|
final(&ctx, &hash)
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_to_buffer_2_4 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) {
|
||||||
|
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_to_buffer_2_4 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) {
|
||||||
|
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||||
|
hash := sum_bytes_2_4(msg, key)
|
||||||
|
_collect_output(dst[:], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_2_4 :: proc {
|
||||||
|
sum_string_2_4,
|
||||||
|
sum_bytes_2_4,
|
||||||
|
sum_string_to_buffer_2_4,
|
||||||
|
sum_bytes_to_buffer_2_4,
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_string :: sum_string_2_4
|
||||||
|
sum_bytes :: sum_bytes_2_4
|
||||||
|
sum_string_to_buffer :: sum_string_to_buffer_2_4
|
||||||
|
sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4
|
||||||
|
sum :: proc {
|
||||||
|
sum_string,
|
||||||
|
sum_bytes,
|
||||||
|
sum_string_to_buffer,
|
||||||
|
sum_bytes_to_buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_u64_2_4 will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||||
|
return sum_bytes_2_4(msg, key) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_bytes will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool {
|
||||||
|
derived_tag: [8]byte
|
||||||
|
sum_bytes_to_buffer_2_4(msg, key, derived_tag[:])
|
||||||
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_2_4 :: proc {
|
||||||
|
verify_bytes_2_4,
|
||||||
|
verify_u64_2_4,
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_bytes :: verify_bytes_2_4
|
||||||
|
verify_u64 :: verify_u64_2_4
|
||||||
|
verify :: proc {
|
||||||
|
verify_bytes,
|
||||||
|
verify_u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_4_8 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_string_4_8 :: proc(msg, key: string) -> u64 {
|
||||||
|
return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_4_8 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 {
|
||||||
|
ctx: Context
|
||||||
|
hash: u64
|
||||||
|
init(&ctx, key, 4, 8)
|
||||||
|
update(&ctx, msg)
|
||||||
|
final(&ctx, &hash)
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_to_buffer_4_8 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) {
|
||||||
|
sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_to_buffer_4_8 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) {
|
||||||
|
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||||
|
hash := sum_bytes_4_8(msg, key)
|
||||||
|
_collect_output(dst[:], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_4_8 :: proc {
|
||||||
|
sum_string_4_8,
|
||||||
|
sum_bytes_4_8,
|
||||||
|
sum_string_to_buffer_4_8,
|
||||||
|
sum_bytes_to_buffer_4_8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_u64_4_8 will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||||
|
return sum_bytes_4_8(msg, key) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_bytes will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool {
|
||||||
|
derived_tag: [8]byte
|
||||||
|
sum_bytes_to_buffer_4_8(msg, key, derived_tag[:])
|
||||||
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_4_8 :: proc {
|
||||||
|
verify_bytes_4_8,
|
||||||
|
verify_u64_4_8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Low level API
|
||||||
|
*/
|
||||||
|
|
||||||
|
init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
|
||||||
|
assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16")
|
||||||
|
ctx.c_rounds = c_rounds
|
||||||
|
ctx.d_rounds = d_rounds
|
||||||
|
is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) ||
|
||||||
|
(ctx.c_rounds == 2 && ctx.d_rounds == 4) ||
|
||||||
|
(ctx.c_rounds == 4 && ctx.d_rounds == 8)
|
||||||
|
assert(is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)")
|
||||||
|
ctx.k0 = util.U64_LE(key[:8])
|
||||||
|
ctx.k1 = util.U64_LE(key[8:])
|
||||||
|
ctx.v0 = 0x736f6d6570736575 ~ ctx.k0
|
||||||
|
ctx.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||||
|
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||||
|
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||||
|
ctx.is_initialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
update :: proc(ctx: ^Context, data: []byte) {
|
||||||
|
assert(ctx.is_initialized, "crypto/siphash: Context is not initialized")
|
||||||
|
ctx.last_block = len(data) / 8 * 8
|
||||||
|
ctx.buf = data
|
||||||
|
i := 0
|
||||||
|
m: u64
|
||||||
|
for i < ctx.last_block {
|
||||||
|
m = u64(ctx.buf[i] & 0xff)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
for r in u64(1)..<8 {
|
||||||
|
m |= u64(ctx.buf[i] & 0xff) << (r * 8)
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.v3 ~= m
|
||||||
|
for _ in 0..<ctx.c_rounds {
|
||||||
|
_compress(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.v0 ~= m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final :: proc(ctx: ^Context, dst: ^u64) {
|
||||||
|
m: u64
|
||||||
|
for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 {
|
||||||
|
m <<= 8
|
||||||
|
m |= u64(ctx.buf[i] & 0xff)
|
||||||
|
}
|
||||||
|
m |= u64(len(ctx.buf) << 56)
|
||||||
|
|
||||||
|
ctx.v3 ~= m
|
||||||
|
|
||||||
|
for _ in 0..<ctx.c_rounds {
|
||||||
|
_compress(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.v0 ~= m
|
||||||
|
ctx.v2 ~= 0xff
|
||||||
|
|
||||||
|
for _ in 0..<ctx.d_rounds {
|
||||||
|
_compress(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst^ = ctx.v0 ~ ctx.v1 ~ ctx.v2 ~ ctx.v3
|
||||||
|
|
||||||
|
reset(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
reset :: proc(ctx: ^Context) {
|
||||||
|
ctx.k0, ctx.k1 = 0, 0
|
||||||
|
ctx.v0, ctx.v1 = 0, 0
|
||||||
|
ctx.v2, ctx.v3 = 0, 0
|
||||||
|
ctx.last_block = 0
|
||||||
|
ctx.c_rounds = 0
|
||||||
|
ctx.d_rounds = 0
|
||||||
|
ctx.is_initialized = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Context :: struct {
|
||||||
|
v0, v1, v2, v3: u64, // State values
|
||||||
|
k0, k1: u64, // Split key
|
||||||
|
c_rounds: int, // Number of message rounds
|
||||||
|
d_rounds: int, // Number of finalization rounds
|
||||||
|
buf: []byte, // Provided data
|
||||||
|
last_block: int, // Offset from the last block
|
||||||
|
is_initialized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||||
|
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) {
|
||||||
|
dst[0] = _get_byte(7, hash)
|
||||||
|
dst[1] = _get_byte(6, hash)
|
||||||
|
dst[2] = _get_byte(5, hash)
|
||||||
|
dst[3] = _get_byte(4, hash)
|
||||||
|
dst[4] = _get_byte(3, hash)
|
||||||
|
dst[5] = _get_byte(2, hash)
|
||||||
|
dst[6] = _get_byte(1, hash)
|
||||||
|
dst[7] = _get_byte(0, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
_compress :: #force_inline proc "contextless" (ctx: ^Context) {
|
||||||
|
ctx.v0 += ctx.v1
|
||||||
|
ctx.v1 = util.ROTL64(ctx.v1, 13)
|
||||||
|
ctx.v1 ~= ctx.v0
|
||||||
|
ctx.v0 = util.ROTL64(ctx.v0, 32)
|
||||||
|
ctx.v2 += ctx.v3
|
||||||
|
ctx.v3 = util.ROTL64(ctx.v3, 16)
|
||||||
|
ctx.v3 ~= ctx.v2
|
||||||
|
ctx.v0 += ctx.v3
|
||||||
|
ctx.v3 = util.ROTL64(ctx.v3, 21)
|
||||||
|
ctx.v3 ~= ctx.v0
|
||||||
|
ctx.v2 += ctx.v1
|
||||||
|
ctx.v1 = util.ROTL64(ctx.v1, 17)
|
||||||
|
ctx.v1 ~= ctx.v2
|
||||||
|
ctx.v2 = util.ROTL64(ctx.v2, 32)
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||||
@@ -122,7 +122,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||||
@@ -124,7 +124,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||||
@@ -203,7 +203,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_192 will hash the given input and write the
|
// hash_bytes_to_buffer_192 will hash the given input and write the
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||||
@@ -124,7 +124,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||||
@@ -203,7 +203,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer_192 will hash the given input and write the
|
// hash_bytes_to_buffer_192 will hash the given input and write the
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
|||||||
// computed hash to the second parameter.
|
// computed hash to the second parameter.
|
||||||
// It requires that the destination buffer is at least as big as the digest size
|
// It requires that the destination buffer is at least as big as the digest size
|
||||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash_bytes_to_buffer will hash the given input and write the
|
// hash_bytes_to_buffer will hash the given input and write the
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
package dynlib
|
package dynlib
|
||||||
|
|
||||||
Library :: distinct rawptr
|
Library :: distinct rawptr
|
||||||
|
|
||||||
|
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||||
|
return _load_library(path, global_symbols)
|
||||||
|
}
|
||||||
|
|
||||||
|
unload_library :: proc(library: Library) -> bool {
|
||||||
|
return _unload_library(library)
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) #optional_ok {
|
||||||
|
return _symbol_address(library, symbol)
|
||||||
|
}
|
||||||
|
|||||||
+15
-14
@@ -1,23 +1,24 @@
|
|||||||
// +build linux, darwin, freebsd
|
//+build linux, darwin, freebsd, openbsd
|
||||||
|
//+private
|
||||||
package dynlib
|
package dynlib
|
||||||
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|
||||||
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||||
flags := os.RTLD_NOW
|
flags := os.RTLD_NOW
|
||||||
if global_symbols {
|
if global_symbols {
|
||||||
flags |= os.RTLD_GLOBAL
|
flags |= os.RTLD_GLOBAL
|
||||||
}
|
}
|
||||||
lib := os.dlopen(path, flags)
|
lib := os.dlopen(path, flags)
|
||||||
return Library(lib), lib != nil
|
return Library(lib), lib != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_library :: proc(library: Library) {
|
_unload_library :: proc(library: Library) -> bool {
|
||||||
os.dlclose(rawptr(library))
|
return os.dlclose(rawptr(library))
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||||
ptr = os.dlsym(rawptr(library), symbol)
|
ptr = os.dlsym(rawptr(library), symbol)
|
||||||
found = ptr != nil
|
found = ptr != nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// +build windows
|
//+build windows
|
||||||
|
//+private
|
||||||
package dynlib
|
package dynlib
|
||||||
|
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||||
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||||
|
|
||||||
wide_path := win32.utf8_to_wstring(path, context.temp_allocator)
|
wide_path := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||||
@@ -12,12 +13,12 @@ load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
|||||||
return handle, handle != nil
|
return handle, handle != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_library :: proc(library: Library) -> bool {
|
_unload_library :: proc(library: Library) -> bool {
|
||||||
ok := win32.FreeLibrary(cast(win32.HMODULE)library)
|
ok := win32.FreeLibrary(cast(win32.HMODULE)library)
|
||||||
return bool(ok)
|
return bool(ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||||
c_str := strings.clone_to_cstring(symbol, context.temp_allocator)
|
c_str := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||||
ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
|
ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
|
||||||
found = ptr != nil
|
found = ptr != nil
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ Reader :: struct {
|
|||||||
// If lazy_quotes is true, a quote may appear in an unquoted field and a non-doubled quote may appear in a quoted field
|
// If lazy_quotes is true, a quote may appear in an unquoted field and a non-doubled quote may appear in a quoted field
|
||||||
lazy_quotes: bool,
|
lazy_quotes: bool,
|
||||||
|
|
||||||
|
// multiline_fields, when set to true, will treat a field starting with a " as a multiline string
|
||||||
|
// therefore, instead of reading until the next \n, it'll read until the next "
|
||||||
|
multiline_fields: bool,
|
||||||
|
|
||||||
// reuse_record controls whether calls to 'read' may return a slice using the backing buffer
|
// reuse_record controls whether calls to 'read' may return a slice using the backing buffer
|
||||||
// for performance
|
// for performance
|
||||||
// By default, each call to 'read' returns a newly allocated slice
|
// By default, each call to 'read' returns a newly allocated slice
|
||||||
@@ -194,32 +198,72 @@ is_valid_delim :: proc(r: rune) -> bool {
|
|||||||
@private
|
@private
|
||||||
_read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.allocator) -> ([]string, Error) {
|
_read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.allocator) -> ([]string, Error) {
|
||||||
read_line :: proc(r: ^Reader) -> ([]byte, io.Error) {
|
read_line :: proc(r: ^Reader) -> ([]byte, io.Error) {
|
||||||
line, err := bufio.reader_read_slice(&r.r, '\n')
|
if !r.multiline_fields {
|
||||||
if err == .Buffer_Full {
|
line, err := bufio.reader_read_slice(&r.r, '\n')
|
||||||
clear(&r.raw_buffer)
|
if err == .Buffer_Full {
|
||||||
append(&r.raw_buffer, ..line)
|
clear(&r.raw_buffer)
|
||||||
for err == .Buffer_Full {
|
|
||||||
line, err = bufio.reader_read_slice(&r.r, '\n')
|
|
||||||
append(&r.raw_buffer, ..line)
|
append(&r.raw_buffer, ..line)
|
||||||
|
for err == .Buffer_Full {
|
||||||
|
line, err = bufio.reader_read_slice(&r.r, '\n')
|
||||||
|
append(&r.raw_buffer, ..line)
|
||||||
|
}
|
||||||
|
line = r.raw_buffer[:]
|
||||||
}
|
}
|
||||||
line = r.raw_buffer[:]
|
if len(line) > 0 && err == .EOF {
|
||||||
}
|
err = nil
|
||||||
if len(line) > 0 && err == .EOF {
|
if line[len(line)-1] == '\r' {
|
||||||
err = nil
|
line = line[:len(line)-1]
|
||||||
if line[len(line)-1] == '\r' {
|
}
|
||||||
line = line[:len(line)-1]
|
|
||||||
}
|
}
|
||||||
}
|
r.line_count += 1
|
||||||
r.line_count += 1
|
|
||||||
|
|
||||||
// normalize \r\n to \n
|
// normalize \r\n to \n
|
||||||
n := len(line)
|
n := len(line)
|
||||||
for n >= 2 && string(line[n-2:]) == "\r\n" {
|
for n >= 2 && string(line[n-2:]) == "\r\n" {
|
||||||
line[n-2] = '\n'
|
line[n-2] = '\n'
|
||||||
line = line[:n-1]
|
line = line[:n-1]
|
||||||
}
|
}
|
||||||
|
return line, err
|
||||||
|
|
||||||
return line, err
|
} else {
|
||||||
|
// Reading a "line" that can possibly contain multiline fields.
|
||||||
|
// Unfortunately, this means we need to read a character at a time.
|
||||||
|
|
||||||
|
err: io.Error
|
||||||
|
cur: rune
|
||||||
|
is_quoted: bool
|
||||||
|
|
||||||
|
field_length := 0
|
||||||
|
|
||||||
|
clear(&r.raw_buffer)
|
||||||
|
|
||||||
|
read_loop: for err == .None {
|
||||||
|
cur, _, err = bufio.reader_read_rune(&r.r)
|
||||||
|
|
||||||
|
if err != .None { break read_loop }
|
||||||
|
|
||||||
|
switch cur {
|
||||||
|
case '"':
|
||||||
|
is_quoted = field_length == 0
|
||||||
|
field_length += 1
|
||||||
|
|
||||||
|
case '\n', '\r':
|
||||||
|
if !is_quoted { break read_loop }
|
||||||
|
|
||||||
|
case r.comma:
|
||||||
|
field_length = 0
|
||||||
|
|
||||||
|
case:
|
||||||
|
field_length += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rune_buf, rune_len := utf8.encode_rune(cur)
|
||||||
|
append(&r.raw_buffer, ..rune_buf[:rune_len])
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.raw_buffer[:], err
|
||||||
|
}
|
||||||
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
length_newline :: proc(b: []byte) -> int {
|
length_newline :: proc(b: []byte) -> int {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Package endian implements sa simple translation between bytes and numbers with
|
||||||
|
specific endian encodings.
|
||||||
|
|
||||||
|
buf: [100]u8
|
||||||
|
put_u16(buf[:], .Little, 16) or_return
|
||||||
|
|
||||||
|
You may ask yourself, why isn't `byte_order` platform Endianness by default, so we can write:
|
||||||
|
put_u16(buf[:], 16) or_return
|
||||||
|
|
||||||
|
The answer is that very few file formats are written in native/platform endianness. Most of them specify the endianness of
|
||||||
|
each of their fields, or use a header field which specifies it for the entire file.
|
||||||
|
|
||||||
|
e.g. a file which specifies it at the top for all fields could do this:
|
||||||
|
file_order := .Little if buf[0] == 0 else .Big
|
||||||
|
field := get_u16(buf[1:], file_order) or_return
|
||||||
|
|
||||||
|
If on the other hand a field is *always* Big-Endian, you're wise to explicitly state it for the benefit of the reader,
|
||||||
|
be that your future self or someone else.
|
||||||
|
|
||||||
|
field := get_u16(buf[:], .Big) or_return
|
||||||
|
*/
|
||||||
|
package encoding_endian
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package encoding_endian
|
||||||
|
|
||||||
|
Byte_Order :: enum u8 {
|
||||||
|
Little,
|
||||||
|
Big,
|
||||||
|
}
|
||||||
|
|
||||||
|
PLATFORM_BYTE_ORDER :: Byte_Order.Little when ODIN_ENDIAN == .Little else Byte_Order.Big
|
||||||
|
|
||||||
|
get_u16 :: proc(b: []byte, order: Byte_Order) -> (v: u16, ok: bool) {
|
||||||
|
if len(b) < 2 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
#no_bounds_check if order == .Little {
|
||||||
|
v = u16(b[0]) | u16(b[1])<<8
|
||||||
|
} else {
|
||||||
|
v = u16(b[1]) | u16(b[0])<<8
|
||||||
|
}
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
get_u32 :: proc(b: []byte, order: Byte_Order) -> (v: u32, ok: bool) {
|
||||||
|
if len(b) < 4 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
#no_bounds_check if order == .Little {
|
||||||
|
v = u32(b[0]) | u32(b[1])<<8 | u32(b[2])<<16 | u32(b[3])<<24
|
||||||
|
} else {
|
||||||
|
v = u32(b[3]) | u32(b[2])<<8 | u32(b[1])<<16 | u32(b[0])<<24
|
||||||
|
}
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
get_u64 :: proc(b: []byte, order: Byte_Order) -> (v: u64, ok: bool) {
|
||||||
|
if len(b) < 8 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
#no_bounds_check if order == .Little {
|
||||||
|
v = u64(b[0]) | u64(b[1])<<8 | u64(b[2])<<16 | u64(b[3])<<24 |
|
||||||
|
u64(b[4])<<32 | u64(b[5])<<40 | u64(b[6])<<48 | u64(b[7])<<56
|
||||||
|
} else {
|
||||||
|
v = u64(b[7]) | u64(b[6])<<8 | u64(b[5])<<16 | u64(b[4])<<24 |
|
||||||
|
u64(b[3])<<32 | u64(b[2])<<40 | u64(b[1])<<48 | u64(b[0])<<56
|
||||||
|
}
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
get_i16 :: proc(b: []byte, order: Byte_Order) -> (i16, bool) {
|
||||||
|
v, ok := get_u16(b, order)
|
||||||
|
return i16(v), ok
|
||||||
|
}
|
||||||
|
get_i32 :: proc(b: []byte, order: Byte_Order) -> (i32, bool) {
|
||||||
|
v, ok := get_u32(b, order)
|
||||||
|
return i32(v), ok
|
||||||
|
}
|
||||||
|
get_i64 :: proc(b: []byte, order: Byte_Order) -> (i64, bool) {
|
||||||
|
v, ok := get_u64(b, order)
|
||||||
|
return i64(v), ok
|
||||||
|
}
|
||||||
|
|
||||||
|
get_f16 :: proc(b: []byte, order: Byte_Order) -> (f16, bool) {
|
||||||
|
v, ok := get_u16(b, order)
|
||||||
|
return transmute(f16)v, ok
|
||||||
|
}
|
||||||
|
get_f32 :: proc(b: []byte, order: Byte_Order) -> (f32, bool) {
|
||||||
|
v, ok := get_u32(b, order)
|
||||||
|
return transmute(f32)v, ok
|
||||||
|
}
|
||||||
|
get_f64 :: proc(b: []byte, order: Byte_Order) -> (f64, bool) {
|
||||||
|
v, ok := get_u64(b, order)
|
||||||
|
return transmute(f64)v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
put_u16 :: proc(b: []byte, order: Byte_Order, v: u16) -> bool {
|
||||||
|
if len(b) < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#no_bounds_check if order == .Little {
|
||||||
|
b[0] = byte(v)
|
||||||
|
b[1] = byte(v >> 8)
|
||||||
|
} else {
|
||||||
|
b[0] = byte(v >> 8)
|
||||||
|
b[1] = byte(v)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
put_u32 :: proc(b: []byte, order: Byte_Order, v: u32) -> bool {
|
||||||
|
if len(b) < 4 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#no_bounds_check if order == .Little {
|
||||||
|
b[0] = byte(v)
|
||||||
|
b[1] = byte(v >> 8)
|
||||||
|
b[2] = byte(v >> 16)
|
||||||
|
b[3] = byte(v >> 24)
|
||||||
|
} else {
|
||||||
|
b[0] = byte(v >> 24)
|
||||||
|
b[1] = byte(v >> 16)
|
||||||
|
b[2] = byte(v >> 8)
|
||||||
|
b[3] = byte(v)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
put_u64 :: proc(b: []byte, order: Byte_Order, v: u64) -> bool {
|
||||||
|
if len(b) < 8 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#no_bounds_check if order == .Little {
|
||||||
|
b[0] = byte(v >> 0)
|
||||||
|
b[1] = byte(v >> 8)
|
||||||
|
b[2] = byte(v >> 16)
|
||||||
|
b[3] = byte(v >> 24)
|
||||||
|
b[4] = byte(v >> 32)
|
||||||
|
b[5] = byte(v >> 40)
|
||||||
|
b[6] = byte(v >> 48)
|
||||||
|
b[7] = byte(v >> 56)
|
||||||
|
} else {
|
||||||
|
b[0] = byte(v >> 56)
|
||||||
|
b[1] = byte(v >> 48)
|
||||||
|
b[2] = byte(v >> 40)
|
||||||
|
b[3] = byte(v >> 32)
|
||||||
|
b[4] = byte(v >> 24)
|
||||||
|
b[5] = byte(v >> 16)
|
||||||
|
b[6] = byte(v >> 8)
|
||||||
|
b[7] = byte(v)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
put_i16 :: proc(b: []byte, order: Byte_Order, v: i16) -> bool {
|
||||||
|
return put_u16(b, order, u16(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
put_i32 :: proc(b: []byte, order: Byte_Order, v: i32) -> bool {
|
||||||
|
return put_u32(b, order, u32(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
put_i64 :: proc(b: []byte, order: Byte_Order, v: i64) -> bool {
|
||||||
|
return put_u64(b, order, u64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
put_f16 :: proc(b: []byte, order: Byte_Order, v: f16) -> bool {
|
||||||
|
return put_u16(b, order, transmute(u16)v)
|
||||||
|
}
|
||||||
|
|
||||||
|
put_f32 :: proc(b: []byte, order: Byte_Order, v: f32) -> bool {
|
||||||
|
return put_u32(b, order, transmute(u32)v)
|
||||||
|
}
|
||||||
|
|
||||||
|
put_f64 :: proc(b: []byte, order: Byte_Order, v: f64) -> bool {
|
||||||
|
return put_u64(b, order, transmute(u64)v)
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# License
|
||||||
|
|
||||||
|
By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions.
|
||||||
|
|
||||||
|
Permission to copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications:
|
||||||
|
|
||||||
|
The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
|
||||||
|
Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software Short Notice should be included (hypertext is preferred, text is permitted) within the body of any redistributed or derivative code.
|
||||||
|
|
||||||
|
Notice of any changes or modifications to the files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.)
|
||||||
|
|
||||||
|
# Disclaimers
|
||||||
|
|
||||||
|
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
|
||||||
|
|
||||||
|
COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
|
||||||
|
|
||||||
|
The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
This version: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
package unicode_entity
|
||||||
|
/*
|
||||||
|
A unicode entity encoder/decoder
|
||||||
|
|
||||||
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-3 license.
|
||||||
|
|
||||||
|
This code has several procedures to map unicode runes to/from different textual encodings.
|
||||||
|
- SGML/XML/HTML entity
|
||||||
|
-- &#<decimal>;
|
||||||
|
-- &#x<hexadecimal>;
|
||||||
|
-- &<entity name>; (If the lookup tables are compiled in).
|
||||||
|
Reference: https://www.w3.org/2003/entities/2007xml/unicode.xml
|
||||||
|
|
||||||
|
- URL encode / decode %hex entity
|
||||||
|
Reference: https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
Jeroen van Rijn: Initial implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "core:unicode/utf8"
|
||||||
|
import "core:unicode"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE)
|
||||||
|
|
||||||
|
write_rune :: strings.write_rune
|
||||||
|
write_string :: strings.write_string
|
||||||
|
|
||||||
|
Error :: enum u8 {
|
||||||
|
None = 0,
|
||||||
|
Tokenizer_Is_Nil,
|
||||||
|
|
||||||
|
Illegal_NUL_Character,
|
||||||
|
Illegal_UTF_Encoding,
|
||||||
|
Illegal_BOM,
|
||||||
|
|
||||||
|
CDATA_Not_Terminated,
|
||||||
|
Comment_Not_Terminated,
|
||||||
|
Invalid_Entity_Encoding,
|
||||||
|
}
|
||||||
|
|
||||||
|
Tokenizer :: struct {
|
||||||
|
r: rune,
|
||||||
|
w: int,
|
||||||
|
|
||||||
|
src: string,
|
||||||
|
offset: int,
|
||||||
|
read_offset: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
CDATA_START :: "<![CDATA["
|
||||||
|
CDATA_END :: "]]>"
|
||||||
|
|
||||||
|
COMMENT_START :: "<!--"
|
||||||
|
COMMENT_END :: "-->"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Default: CDATA and comments are passed through unchanged.
|
||||||
|
*/
|
||||||
|
XML_Decode_Option :: enum u8 {
|
||||||
|
/*
|
||||||
|
Do not decode & entities. It decodes by default.
|
||||||
|
If given, overrides `Decode_CDATA`.
|
||||||
|
*/
|
||||||
|
No_Entity_Decode,
|
||||||
|
|
||||||
|
/*
|
||||||
|
CDATA is unboxed.
|
||||||
|
*/
|
||||||
|
Unbox_CDATA,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Unboxed CDATA is decoded as well.
|
||||||
|
Ignored if `.Unbox_CDATA` is not given.
|
||||||
|
*/
|
||||||
|
Decode_CDATA,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Comments are stripped.
|
||||||
|
*/
|
||||||
|
Comment_Strip,
|
||||||
|
}
|
||||||
|
XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
|
||||||
|
|
||||||
|
/*
|
||||||
|
Decode a string that may include SGML/XML/HTML entities.
|
||||||
|
The caller has to free the result.
|
||||||
|
*/
|
||||||
|
decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
|
l := len(input)
|
||||||
|
if l == 0 { return "", .None }
|
||||||
|
|
||||||
|
builder := strings.builder_make()
|
||||||
|
defer strings.builder_destroy(&builder)
|
||||||
|
|
||||||
|
t := Tokenizer{src=input}
|
||||||
|
in_data := false
|
||||||
|
|
||||||
|
loop: for {
|
||||||
|
advance(&t) or_return
|
||||||
|
if t.r < 0 { break loop }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Below here we're never inside a CDATA tag.
|
||||||
|
At most we'll see the start of one, but that doesn't affect the logic.
|
||||||
|
*/
|
||||||
|
switch t.r {
|
||||||
|
case '<':
|
||||||
|
/*
|
||||||
|
Might be the start of a CDATA tag or comment.
|
||||||
|
|
||||||
|
We don't need to check if we need to write a `<`, because if it isn't CDATA or a comment,
|
||||||
|
it couldn't have been part of an XML tag body to be decoded here.
|
||||||
|
|
||||||
|
Keep in mind that we could already *be* inside a CDATA tag.
|
||||||
|
If so, write `>` as a literal and continue.
|
||||||
|
*/
|
||||||
|
if in_data {
|
||||||
|
write_rune(&builder, '<')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
in_data = _handle_xml_special(&t, &builder, options) or_return
|
||||||
|
|
||||||
|
case ']':
|
||||||
|
/*
|
||||||
|
If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
|
||||||
|
*/
|
||||||
|
if in_data {
|
||||||
|
if t.read_offset + len(CDATA_END) < len(t.src) {
|
||||||
|
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
|
||||||
|
in_data = false
|
||||||
|
t.read_offset += len(CDATA_END) - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
write_rune(&builder, ']')
|
||||||
|
}
|
||||||
|
|
||||||
|
case:
|
||||||
|
if in_data && .Decode_CDATA not_in options {
|
||||||
|
/*
|
||||||
|
Unboxed, but undecoded.
|
||||||
|
*/
|
||||||
|
write_rune(&builder, t.r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.r == '&' {
|
||||||
|
if entity, entity_err := _extract_xml_entity(&t); entity_err != .None {
|
||||||
|
/*
|
||||||
|
We read to the end of the string without closing the entity.
|
||||||
|
Pass through as-is.
|
||||||
|
*/
|
||||||
|
write_string(&builder, entity)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if .No_Entity_Decode not_in options {
|
||||||
|
if decoded, ok := xml_decode_entity(entity); ok {
|
||||||
|
write_rune(&builder, decoded)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Literal passthrough because the decode failed or we want entities not decoded.
|
||||||
|
*/
|
||||||
|
write_string(&builder, "&")
|
||||||
|
write_string(&builder, entity)
|
||||||
|
write_string(&builder, ";")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write_rune(&builder, t.r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.clone(strings.to_string(builder), allocator), err
|
||||||
|
}
|
||||||
|
|
||||||
|
advance :: proc(t: ^Tokenizer) -> (err: Error) {
|
||||||
|
if t == nil { return .Tokenizer_Is_Nil }
|
||||||
|
using t
|
||||||
|
|
||||||
|
#no_bounds_check {
|
||||||
|
if read_offset < len(src) {
|
||||||
|
offset = read_offset
|
||||||
|
r, w = rune(src[read_offset]), 1
|
||||||
|
switch {
|
||||||
|
case r == 0:
|
||||||
|
return .Illegal_NUL_Character
|
||||||
|
case r >= utf8.RUNE_SELF:
|
||||||
|
r, w = utf8.decode_rune_in_string(src[read_offset:])
|
||||||
|
if r == utf8.RUNE_ERROR && w == 1 {
|
||||||
|
return .Illegal_UTF_Encoding
|
||||||
|
} else if r == utf8.RUNE_BOM && offset > 0 {
|
||||||
|
return .Illegal_BOM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read_offset += w
|
||||||
|
return .None
|
||||||
|
} else {
|
||||||
|
offset = len(src)
|
||||||
|
r = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) {
|
||||||
|
entity := entity
|
||||||
|
if len(entity) == 0 { return -1, false }
|
||||||
|
|
||||||
|
switch entity[0] {
|
||||||
|
case '#':
|
||||||
|
base := 10
|
||||||
|
val := 0
|
||||||
|
entity = entity[1:]
|
||||||
|
|
||||||
|
if len(entity) == 0 { return -1, false }
|
||||||
|
|
||||||
|
if entity[0] == 'x' || entity[0] == 'X' {
|
||||||
|
base = 16
|
||||||
|
entity = entity[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(entity) > 0 {
|
||||||
|
r := entity[0]
|
||||||
|
switch r {
|
||||||
|
case '0'..='9':
|
||||||
|
val *= base
|
||||||
|
val += int(r - '0')
|
||||||
|
|
||||||
|
case 'a'..='f':
|
||||||
|
if base == 10 { return -1, false }
|
||||||
|
val *= base
|
||||||
|
val += int(r - 'a' + 10)
|
||||||
|
|
||||||
|
case 'A'..='F':
|
||||||
|
if base == 10 { return -1, false }
|
||||||
|
val *= base
|
||||||
|
val += int(r - 'A' + 10)
|
||||||
|
|
||||||
|
case:
|
||||||
|
return -1, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if val > MAX_RUNE_CODEPOINT { return -1, false }
|
||||||
|
entity = entity[1:]
|
||||||
|
}
|
||||||
|
return rune(val), true
|
||||||
|
|
||||||
|
case:
|
||||||
|
/*
|
||||||
|
Named entity.
|
||||||
|
*/
|
||||||
|
return named_xml_entity_to_rune(entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Private XML helper to extract `&<stuff>;` entity.
|
||||||
|
*/
|
||||||
|
@(private="file")
|
||||||
|
_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
|
||||||
|
assert(t != nil && t.r == '&')
|
||||||
|
|
||||||
|
/*
|
||||||
|
All of these would be in the ASCII range.
|
||||||
|
Even if one is not, it doesn't matter. All characters we need to compare to extract are.
|
||||||
|
*/
|
||||||
|
using t
|
||||||
|
|
||||||
|
length := len(t.src)
|
||||||
|
found := false
|
||||||
|
|
||||||
|
#no_bounds_check {
|
||||||
|
for read_offset < length {
|
||||||
|
if src[read_offset] == ';' {
|
||||||
|
found = true
|
||||||
|
read_offset += 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
read_offset += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return string(src[offset + 1 : read_offset - 1]), .None
|
||||||
|
}
|
||||||
|
return string(src[offset : read_offset]), .Invalid_Entity_Encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Private XML helper for CDATA and comments.
|
||||||
|
*/
|
||||||
|
@(private="file")
|
||||||
|
_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
|
||||||
|
assert(t != nil && t.r == '<')
|
||||||
|
if t.read_offset + len(CDATA_START) >= len(t.src) { return false, .None }
|
||||||
|
|
||||||
|
if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START {
|
||||||
|
t.read_offset += len(CDATA_START) - 1
|
||||||
|
|
||||||
|
if .Unbox_CDATA in options && .Decode_CDATA in options {
|
||||||
|
/*
|
||||||
|
We're unboxing _and_ decoding CDATA
|
||||||
|
*/
|
||||||
|
return true, .None
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CDATA is passed through.
|
||||||
|
*/
|
||||||
|
offset := t.offset
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scan until end of CDATA.
|
||||||
|
*/
|
||||||
|
for {
|
||||||
|
advance(t) or_return
|
||||||
|
if t.r < 0 { return true, .CDATA_Not_Terminated }
|
||||||
|
|
||||||
|
if t.read_offset + len(CDATA_END) < len(t.src) {
|
||||||
|
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
|
||||||
|
t.read_offset += len(CDATA_END) - 1
|
||||||
|
|
||||||
|
cdata := string(t.src[offset : t.read_offset])
|
||||||
|
|
||||||
|
if .Unbox_CDATA in options {
|
||||||
|
cdata = cdata[len(CDATA_START):]
|
||||||
|
cdata = cdata[:len(cdata) - len(CDATA_END)]
|
||||||
|
}
|
||||||
|
|
||||||
|
write_string(builder, cdata)
|
||||||
|
return false, .None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START {
|
||||||
|
t.read_offset += len(COMMENT_START)
|
||||||
|
/*
|
||||||
|
Comment is passed through by default.
|
||||||
|
*/
|
||||||
|
offset := t.offset
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scan until end of Comment.
|
||||||
|
*/
|
||||||
|
for {
|
||||||
|
advance(t) or_return
|
||||||
|
if t.r < 0 { return true, .Comment_Not_Terminated }
|
||||||
|
|
||||||
|
if t.read_offset + len(COMMENT_END) < len(t.src) {
|
||||||
|
if string(t.src[t.offset:][:len(COMMENT_END)]) == COMMENT_END {
|
||||||
|
t.read_offset += len(COMMENT_END) - 1
|
||||||
|
|
||||||
|
if .Comment_Strip not_in options {
|
||||||
|
comment := string(t.src[offset : t.read_offset])
|
||||||
|
write_string(builder, comment)
|
||||||
|
}
|
||||||
|
return false, .None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return false, .None
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package unicode_entity_example
|
||||||
|
|
||||||
|
import "core:encoding/xml"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:mem"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:time"
|
||||||
|
|
||||||
|
doc_print :: proc(doc: ^xml.Document) {
|
||||||
|
buf: strings.Builder
|
||||||
|
defer strings.builder_destroy(&buf)
|
||||||
|
w := strings.to_writer(&buf)
|
||||||
|
|
||||||
|
xml.print(w, doc)
|
||||||
|
fmt.println(strings.to_string(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
_entities :: proc() {
|
||||||
|
doc: ^xml.Document
|
||||||
|
err: xml.Error
|
||||||
|
|
||||||
|
DOC :: #load("../../../../tests/core/assets/XML/unicode.xml")
|
||||||
|
|
||||||
|
OPTIONS :: xml.Options{
|
||||||
|
flags = {
|
||||||
|
.Ignore_Unsupported, .Intern_Comments,
|
||||||
|
},
|
||||||
|
expected_doctype = "",
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_duration: time.Duration
|
||||||
|
|
||||||
|
{
|
||||||
|
time.SCOPED_TICK_DURATION(&parse_duration)
|
||||||
|
doc, err = xml.parse(DOC, OPTIONS)
|
||||||
|
}
|
||||||
|
defer xml.destroy(doc)
|
||||||
|
|
||||||
|
doc_print(doc)
|
||||||
|
|
||||||
|
ms := time.duration_milliseconds(parse_duration)
|
||||||
|
|
||||||
|
speed := (f64(1000.0) / ms) * f64(len(DOC)) / 1_024.0 / 1_024.0
|
||||||
|
|
||||||
|
fmt.printf("Parse time: %.2f ms (%.2f MiB/s).\n", ms, speed)
|
||||||
|
fmt.printf("Error: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_main :: proc() {
|
||||||
|
using fmt
|
||||||
|
|
||||||
|
options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }}
|
||||||
|
|
||||||
|
doc, _ := xml.parse(#load("test.html"), options)
|
||||||
|
|
||||||
|
defer xml.destroy(doc)
|
||||||
|
doc_print(doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
using fmt
|
||||||
|
|
||||||
|
track: mem.Tracking_Allocator
|
||||||
|
mem.tracking_allocator_init(&track, context.allocator)
|
||||||
|
context.allocator = mem.tracking_allocator(&track)
|
||||||
|
|
||||||
|
// _main()
|
||||||
|
_entities()
|
||||||
|
|
||||||
|
if len(track.allocation_map) > 0 {
|
||||||
|
println()
|
||||||
|
for _, v in track.allocation_map {
|
||||||
|
printf("%v Leaked %v bytes.\n", v.location, v.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Entity Reference Test</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: #000; color: #eee;
|
||||||
|
width: 40%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
font-size: 14pt;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Entity Reference Test</h1>
|
||||||
|
<div id="test_cdata_in_comment" foo="">
|
||||||
|
Foozle]! © <!-- <![CDATA[ ® ]]> -->42&;1234&
|
||||||
|
</div>
|
||||||
|
<!-- EXPECTED: Foozle]! © 42&;1234& -->
|
||||||
|
<div id="test_cdata_unwrap_and_passthrough">
|
||||||
|
Foozle]! © <![CDATA[BOX ® /BOX]]>42&;1234&
|
||||||
|
</div>
|
||||||
|
<!-- EXPECTED: Foozle]! © BOX ® /BOX42&;1234& -->
|
||||||
|
<div>
|
||||||
|
| | | fj ` \ ® ϱ ∳ ⁏
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@
|
|||||||
// Construction history, or BSP trees would make the format too large to serve its purpose.
|
// Construction history, or BSP trees would make the format too large to serve its purpose.
|
||||||
// The facilities of the formats to store meta data should make the format flexible enough
|
// The facilities of the formats to store meta data should make the format flexible enough
|
||||||
// for most uses. Adding HxA support should be something anyone can do in a days work.
|
// for most uses. Adding HxA support should be something anyone can do in a days work.
|
||||||
|
//
|
||||||
// Structure:
|
// Structure:
|
||||||
// ----------
|
// ----------
|
||||||
// HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
|
// HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
|
||||||
@@ -45,17 +45,17 @@
|
|||||||
// of a number of named layers. All layers in the stack have the same number of elements. Each layer
|
// of a number of named layers. All layers in the stack have the same number of elements. Each layer
|
||||||
// describes one property of the primitive. Each layer can have multiple channels and each layer can
|
// describes one property of the primitive. Each layer can have multiple channels and each layer can
|
||||||
// store data of a different type.
|
// store data of a different type.
|
||||||
|
//
|
||||||
// HaX stores 3 kinds of nodes
|
// HaX stores 3 kinds of nodes
|
||||||
// - Pixel data.
|
// - Pixel data.
|
||||||
// - Polygon geometry data.
|
// - Polygon geometry data.
|
||||||
// - Meta data only.
|
// - Meta data only.
|
||||||
|
//
|
||||||
// Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
|
// Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
|
||||||
// Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
|
// Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
|
||||||
// layers to store things like color. The length of the layer stack is determined by the type and
|
// layers to store things like color. The length of the layer stack is determined by the type and
|
||||||
// dimensions stored in the
|
// dimensions stored in the
|
||||||
|
//
|
||||||
// Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
|
// Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
|
||||||
// vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
|
// vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
|
||||||
// layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
|
// layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
// for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
|
// for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
|
||||||
// integer layer named "index" describing the vertices used to form polygons. The last value in each
|
// integer layer named "index" describing the vertices used to form polygons. The last value in each
|
||||||
// polygon has a negative - 1 index to indicate the end of the polygon.
|
// polygon has a negative - 1 index to indicate the end of the polygon.
|
||||||
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// A quad and a tri with the vertex index:
|
// A quad and a tri with the vertex index:
|
||||||
// [0, 1, 2, 3] [1, 4, 2]
|
// [0, 1, 2, 3] [1, 4, 2]
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
// The face stack stores values per face. the length of the face stack has to match the number of
|
// The face stack stores values per face. the length of the face stack has to match the number of
|
||||||
// negative values in the index layer in the corner stack. The face stack can be used to store things
|
// negative values in the index layer in the corner stack. The face stack can be used to store things
|
||||||
// like material index.
|
// like material index.
|
||||||
|
//
|
||||||
// Storage
|
// Storage
|
||||||
// -------
|
// -------
|
||||||
// All data is stored in little endian byte order with no padding. The layout mirrors the structs
|
// All data is stored in little endian byte order with no padding. The layout mirrors the structs
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ Node :: struct {
|
|||||||
/* Conventions */
|
/* Conventions */
|
||||||
/* ------------
|
/* ------------
|
||||||
Much of HxA's use is based on convention. HxA lets users store arbitrary data in its structure that can be parsed but whose semantic meaning does not need to be understood.
|
Much of HxA's use is based on convention. HxA lets users store arbitrary data in its structure that can be parsed but whose semantic meaning does not need to be understood.
|
||||||
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basicly recomendations of how to store common data.
|
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basically recomendations of how to store common data.
|
||||||
If you use HxA for something not covered by the conventions but need a convention for your use case. Please let us know so that we can add it!
|
If you use HxA for something not covered by the conventions but need a convention for your use case. Please let us know so that we can add it!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
read_value :: proc(r: ^Reader, $T: typeid) -> (value: T, err: Read_Error) {
|
read_value :: proc(r: ^Reader, $T: typeid) -> (value: T, err: Read_Error) {
|
||||||
remaining := len(r.data) - r.offset
|
remaining := len(r.data) - r.offset
|
||||||
if remaining < size_of(T) {
|
if remaining < size_of(T) {
|
||||||
|
if r.print_error {
|
||||||
|
fmt.eprintf("file '%s' failed to read value at offset %v\n", r.filename, r.offset)
|
||||||
|
}
|
||||||
err = .Short_Read
|
err = .Short_Read
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -51,6 +54,10 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
read_array :: proc(r: ^Reader, $T: typeid, count: int) -> (value: []T, err: Read_Error) {
|
read_array :: proc(r: ^Reader, $T: typeid, count: int) -> (value: []T, err: Read_Error) {
|
||||||
remaining := len(r.data) - r.offset
|
remaining := len(r.data) - r.offset
|
||||||
if remaining < size_of(T)*count {
|
if remaining < size_of(T)*count {
|
||||||
|
if r.print_error {
|
||||||
|
fmt.eprintf("file '%s' failed to read array of %d elements at offset %v\n",
|
||||||
|
r.filename, count, r.offset)
|
||||||
|
}
|
||||||
err = .Short_Read
|
err = .Short_Read
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -82,7 +89,8 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
type := read_value(r, Meta_Value_Type) or_return
|
type := read_value(r, Meta_Value_Type) or_return
|
||||||
if type > max(Meta_Value_Type) {
|
if type > max(Meta_Value_Type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type)))
|
fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is %d\n",
|
||||||
|
r.filename, u8(type), u8(max(Meta_Value_Type)))
|
||||||
}
|
}
|
||||||
err = .Invalid_Data
|
err = .Invalid_Data
|
||||||
return
|
return
|
||||||
@@ -114,7 +122,8 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
type := read_value(r, Layer_Data_Type) or_return
|
type := read_value(r, Layer_Data_Type) or_return
|
||||||
if type > max(type) {
|
if type > max(type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type)))
|
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is %d\n",
|
||||||
|
r.filename, u8(type), u8(max(Layer_Data_Type)))
|
||||||
}
|
}
|
||||||
err = .Invalid_Data
|
err = .Invalid_Data
|
||||||
return
|
return
|
||||||
@@ -134,13 +143,23 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(data) < size_of(Header) {
|
if len(data) < size_of(Header) {
|
||||||
|
if print_error {
|
||||||
|
fmt.eprintf("HxA Error: file '%s' has no header\n", filename)
|
||||||
|
}
|
||||||
|
err = .Short_Read
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
header := cast(^Header)raw_data(data)
|
header := cast(^Header)raw_data(data)
|
||||||
assert(header.magic_number == MAGIC_NUMBER)
|
if (header.magic_number != MAGIC_NUMBER) {
|
||||||
|
if print_error {
|
||||||
|
fmt.eprintf("HxA Error: file '%s' has invalid magic number 0x%x\n", filename, header.magic_number)
|
||||||
|
}
|
||||||
|
err = .Invalid_Data
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r := &Reader{
|
r := &Reader{
|
||||||
filename = filename,
|
filename = filename,
|
||||||
@@ -150,6 +169,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
|
|
||||||
node_count := 0
|
node_count := 0
|
||||||
|
file.header = header^
|
||||||
file.nodes = make([]Node, header.internal_node_count)
|
file.nodes = make([]Node, header.internal_node_count)
|
||||||
defer if err != nil {
|
defer if err != nil {
|
||||||
nodes_destroy(file.nodes)
|
nodes_destroy(file.nodes)
|
||||||
@@ -162,7 +182,8 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
type := read_value(r, Node_Type) or_return
|
type := read_value(r, Node_Type) or_return
|
||||||
if type > max(Node_Type) {
|
if type > max(Node_Type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type)))
|
fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is %d\n",
|
||||||
|
r.filename, u8(type), u8(max(Node_Type)))
|
||||||
}
|
}
|
||||||
err = .Invalid_Data
|
err = .Invalid_Data
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ write_internal :: proc(w: ^Writer, file: File) {
|
|||||||
|
|
||||||
write_metadata :: proc(w: ^Writer, meta_data: []Meta) {
|
write_metadata :: proc(w: ^Writer, meta_data: []Meta) {
|
||||||
for m in meta_data {
|
for m in meta_data {
|
||||||
name_len := max(len(m.name), 255)
|
name_len := min(len(m.name), 255)
|
||||||
write_value(w, u8(name_len))
|
write_value(w, u8(name_len))
|
||||||
write_string(w, m.name[:name_len])
|
write_string(w, m.name[:name_len])
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ write_internal :: proc(w: ^Writer, file: File) {
|
|||||||
write_layer_stack :: proc(w: ^Writer, layers: Layer_Stack) {
|
write_layer_stack :: proc(w: ^Writer, layers: Layer_Stack) {
|
||||||
write_value(w, u32(len(layers)))
|
write_value(w, u32(len(layers)))
|
||||||
for layer in layers {
|
for layer in layers {
|
||||||
name_len := max(len(layer.name), 255)
|
name_len := min(len(layer.name), 255)
|
||||||
write_value(w, u8(name_len))
|
write_value(w, u8(name_len))
|
||||||
write_string(w, layer .name[:name_len])
|
write_string(w, layer .name[:name_len])
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ write_internal :: proc(w: ^Writer, file: File) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
write_value(w, &Header{
|
write_value(w, Header{
|
||||||
magic_number = MAGIC_NUMBER,
|
magic_number = MAGIC_NUMBER,
|
||||||
version = LATEST_VERSION,
|
version = LATEST_VERSION,
|
||||||
internal_node_count = u32le(len(file.nodes)),
|
internal_node_count = u32le(len(file.nodes)),
|
||||||
|
|||||||
+224
-48
@@ -8,33 +8,63 @@ import "core:strings"
|
|||||||
import "core:io"
|
import "core:io"
|
||||||
|
|
||||||
Marshal_Data_Error :: enum {
|
Marshal_Data_Error :: enum {
|
||||||
|
None,
|
||||||
Unsupported_Type,
|
Unsupported_Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
Marshal_Error :: union {
|
Marshal_Error :: union #shared_nil {
|
||||||
Marshal_Data_Error,
|
Marshal_Data_Error,
|
||||||
io.Error,
|
io.Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
|
// careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results
|
||||||
b := strings.make_builder(allocator)
|
Marshal_Options :: struct {
|
||||||
defer if err != .None {
|
// output based on spec
|
||||||
strings.destroy_builder(&b)
|
spec: Specification,
|
||||||
|
|
||||||
|
// use line breaks & tab|spaces
|
||||||
|
pretty: bool,
|
||||||
|
|
||||||
|
// spacing
|
||||||
|
use_spaces: bool,
|
||||||
|
spaces: int,
|
||||||
|
|
||||||
|
// state
|
||||||
|
indentation: int,
|
||||||
|
|
||||||
|
// option to output uint in JSON5 & MJSON
|
||||||
|
write_uint_as_hex: bool,
|
||||||
|
|
||||||
|
// mjson output options
|
||||||
|
mjson_keys_use_quotes: bool,
|
||||||
|
mjson_keys_use_equal_sign: bool,
|
||||||
|
|
||||||
|
// mjson state
|
||||||
|
mjson_skipped_first_braces_start: bool,
|
||||||
|
mjson_skipped_first_braces_end: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
|
||||||
|
b := strings.builder_make(allocator)
|
||||||
|
defer if err != nil {
|
||||||
|
strings.builder_destroy(&b)
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal_to_builder(&b, v) or_return
|
opt := opt
|
||||||
|
marshal_to_builder(&b, v, &opt) or_return
|
||||||
|
|
||||||
if len(b.buf) != 0 {
|
if len(b.buf) != 0 {
|
||||||
data = b.buf[:]
|
data = b.buf[:]
|
||||||
}
|
}
|
||||||
return data, .None
|
|
||||||
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> Marshal_Error {
|
||||||
return marshal_to_writer(strings.to_writer(b), v)
|
return marshal_to_writer(strings.to_writer(b), v, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
io.write_string(w, "null") or_return
|
io.write_string(w, "null") or_return
|
||||||
return
|
return
|
||||||
@@ -48,13 +78,14 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
unreachable()
|
unreachable()
|
||||||
|
|
||||||
case runtime.Type_Info_Integer:
|
case runtime.Type_Info_Integer:
|
||||||
buf: [21]byte
|
buf: [40]byte
|
||||||
u: u128
|
u: u128
|
||||||
switch i in a {
|
switch i in a {
|
||||||
case i8: u = u128(i)
|
case i8: u = u128(i)
|
||||||
case i16: u = u128(i)
|
case i16: u = u128(i)
|
||||||
case i32: u = u128(i)
|
case i32: u = u128(i)
|
||||||
case i64: u = u128(i)
|
case i64: u = u128(i)
|
||||||
|
case i128: u = u128(i)
|
||||||
case int: u = u128(i)
|
case int: u = u128(i)
|
||||||
case u8: u = u128(i)
|
case u8: u = u128(i)
|
||||||
case u16: u = u128(i)
|
case u16: u = u128(i)
|
||||||
@@ -81,7 +112,21 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
case u128be: u = u128(i)
|
case u128be: u = u128(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
s: string
|
||||||
|
|
||||||
|
// allow uints to be printed as hex
|
||||||
|
if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) {
|
||||||
|
switch i in a {
|
||||||
|
case u8, u16, u32, u64, u128:
|
||||||
|
s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
|
||||||
|
|
||||||
|
case:
|
||||||
|
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
||||||
|
}
|
||||||
|
|
||||||
io.write_string(w, s) or_return
|
io.write_string(w, s) or_return
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +191,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
case runtime.Type_Info_Multi_Pointer:
|
case runtime.Type_Info_Multi_Pointer:
|
||||||
return .Unsupported_Type
|
return .Unsupported_Type
|
||||||
|
|
||||||
|
case runtime.Type_Info_Soa_Pointer:
|
||||||
|
return .Unsupported_Type
|
||||||
|
|
||||||
case runtime.Type_Info_Procedure:
|
case runtime.Type_Info_Procedure:
|
||||||
return .Unsupported_Type
|
return .Unsupported_Type
|
||||||
|
|
||||||
@@ -165,52 +213,48 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
return .Unsupported_Type
|
return .Unsupported_Type
|
||||||
|
|
||||||
case runtime.Type_Info_Array:
|
case runtime.Type_Info_Array:
|
||||||
io.write_byte(w, '[') or_return
|
opt_write_start(w, opt, '[') or_return
|
||||||
for i in 0..<info.count {
|
for i in 0..<info.count {
|
||||||
if i > 0 { io.write_string(w, ", ") or_return }
|
opt_write_iteration(w, opt, i) or_return
|
||||||
|
|
||||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||||
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
|
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
|
||||||
}
|
}
|
||||||
io.write_byte(w, ']') or_return
|
opt_write_end(w, opt, ']') or_return
|
||||||
|
|
||||||
case runtime.Type_Info_Enumerated_Array:
|
case runtime.Type_Info_Enumerated_Array:
|
||||||
index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum)
|
index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum)
|
||||||
io.write_byte(w, '[') or_return
|
opt_write_start(w, opt, '[') or_return
|
||||||
for i in 0..<info.count {
|
for i in 0..<info.count {
|
||||||
if i > 0 { io.write_string(w, ", ") or_return }
|
opt_write_iteration(w, opt, i) or_return
|
||||||
|
|
||||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||||
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
|
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
|
||||||
}
|
}
|
||||||
io.write_byte(w, ']') or_return
|
opt_write_end(w, opt, ']') or_return
|
||||||
|
|
||||||
case runtime.Type_Info_Dynamic_Array:
|
case runtime.Type_Info_Dynamic_Array:
|
||||||
io.write_byte(w, '[') or_return
|
opt_write_start(w, opt, '[') or_return
|
||||||
array := cast(^mem.Raw_Dynamic_Array)v.data
|
array := cast(^mem.Raw_Dynamic_Array)v.data
|
||||||
for i in 0..<array.len {
|
for i in 0..<array.len {
|
||||||
if i > 0 { io.write_string(w, ", ") or_return }
|
opt_write_iteration(w, opt, i) or_return
|
||||||
|
|
||||||
data := uintptr(array.data) + uintptr(i*info.elem_size)
|
data := uintptr(array.data) + uintptr(i*info.elem_size)
|
||||||
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
|
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
|
||||||
}
|
}
|
||||||
io.write_byte(w, ']') or_return
|
opt_write_end(w, opt, ']') or_return
|
||||||
|
|
||||||
case runtime.Type_Info_Slice:
|
case runtime.Type_Info_Slice:
|
||||||
io.write_byte(w, '[') or_return
|
opt_write_start(w, opt, '[') or_return
|
||||||
slice := cast(^mem.Raw_Slice)v.data
|
slice := cast(^mem.Raw_Slice)v.data
|
||||||
for i in 0..<slice.len {
|
for i in 0..<slice.len {
|
||||||
if i > 0 { io.write_string(w, ", ") or_return }
|
opt_write_iteration(w, opt, i) or_return
|
||||||
|
|
||||||
data := uintptr(slice.data) + uintptr(i*info.elem_size)
|
data := uintptr(slice.data) + uintptr(i*info.elem_size)
|
||||||
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
|
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
|
||||||
}
|
}
|
||||||
io.write_byte(w, ']') or_return
|
opt_write_end(w, opt, ']') or_return
|
||||||
|
|
||||||
case runtime.Type_Info_Map:
|
case runtime.Type_Info_Map:
|
||||||
m := (^mem.Raw_Map)(v.data)
|
m := (^mem.Raw_Map)(v.data)
|
||||||
|
opt_write_start(w, opt, '{') or_return
|
||||||
|
|
||||||
io.write_byte(w, '{') or_return
|
|
||||||
if m != nil {
|
if m != nil {
|
||||||
if info.generated_struct == nil {
|
if info.generated_struct == nil {
|
||||||
return .Unsupported_Type
|
return .Unsupported_Type
|
||||||
@@ -222,31 +266,50 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
entry_size := ed.elem_size
|
entry_size := ed.elem_size
|
||||||
|
|
||||||
for i in 0..<entries.len {
|
for i in 0..<entries.len {
|
||||||
if i > 0 { io.write_string(w, ", ") or_return }
|
opt_write_iteration(w, opt, i) or_return
|
||||||
|
|
||||||
data := uintptr(entries.data) + uintptr(i*entry_size)
|
data := uintptr(entries.data) + uintptr(i*entry_size)
|
||||||
key := rawptr(data + entry_type.offsets[2])
|
key := rawptr(data + entry_type.offsets[2])
|
||||||
value := rawptr(data + entry_type.offsets[3])
|
value := rawptr(data + entry_type.offsets[3])
|
||||||
|
|
||||||
marshal_to_writer(w, any{key, info.key.id}) or_return
|
// check for string type
|
||||||
io.write_string(w, ": ") or_return
|
{
|
||||||
marshal_to_writer(w, any{value, info.value.id}) or_return
|
v := any{key, info.key.id}
|
||||||
|
ti := runtime.type_info_base(type_info_of(v.id))
|
||||||
|
a := any{v.data, ti.id}
|
||||||
|
name: string
|
||||||
|
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case runtime.Type_Info_String:
|
||||||
|
switch s in a {
|
||||||
|
case string: name = s
|
||||||
|
case cstring: name = string(s)
|
||||||
|
}
|
||||||
|
opt_write_key(w, opt, name) or_return
|
||||||
|
|
||||||
|
case: return .Unsupported_Type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal_to_writer(w, any{value, info.value.id}, opt) or_return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
io.write_byte(w, '}') or_return
|
|
||||||
|
opt_write_end(w, opt, '}') or_return
|
||||||
|
|
||||||
case runtime.Type_Info_Struct:
|
case runtime.Type_Info_Struct:
|
||||||
io.write_byte(w, '{') or_return
|
opt_write_start(w, opt, '{') or_return
|
||||||
|
|
||||||
for name, i in info.names {
|
for name, i in info.names {
|
||||||
if i > 0 { io.write_string(w, ", ") or_return }
|
opt_write_iteration(w, opt, i) or_return
|
||||||
io.write_quoted_string(w, name) or_return
|
opt_write_key(w, opt, name) or_return
|
||||||
io.write_string(w, ": ") or_return
|
|
||||||
|
|
||||||
id := info.types[i].id
|
id := info.types[i].id
|
||||||
data := rawptr(uintptr(v.data) + info.offsets[i])
|
data := rawptr(uintptr(v.data) + info.offsets[i])
|
||||||
marshal_to_writer(w, any{data, id}) or_return
|
marshal_to_writer(w, any{data, id}, opt) or_return
|
||||||
}
|
}
|
||||||
io.write_byte(w, '}') or_return
|
|
||||||
|
opt_write_end(w, opt, '}') or_return
|
||||||
|
|
||||||
case runtime.Type_Info_Union:
|
case runtime.Type_Info_Union:
|
||||||
tag_ptr := uintptr(v.data) + info.tag_offset
|
tag_ptr := uintptr(v.data) + info.tag_offset
|
||||||
@@ -269,11 +332,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
io.write_string(w, "null") or_return
|
io.write_string(w, "null") or_return
|
||||||
} else {
|
} else {
|
||||||
id := info.variants[tag-1].id
|
id := info.variants[tag-1].id
|
||||||
return marshal_to_writer(w, any{v.data, id})
|
return marshal_to_writer(w, any{v.data, id}, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
case runtime.Type_Info_Enum:
|
case runtime.Type_Info_Enum:
|
||||||
return marshal_to_writer(w, any{v.data, info.base.id})
|
return marshal_to_writer(w, any{v.data, info.base.id}, opt)
|
||||||
|
|
||||||
case runtime.Type_Info_Bit_Set:
|
case runtime.Type_Info_Bit_Set:
|
||||||
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
|
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
|
||||||
@@ -285,8 +348,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
case runtime.Type_Info_Integer:
|
case runtime.Type_Info_Integer:
|
||||||
switch info.endianness {
|
switch info.endianness {
|
||||||
case .Platform: return false
|
case .Platform: return false
|
||||||
case .Little: return ODIN_ENDIAN != "little"
|
case .Little: return ODIN_ENDIAN != .Little
|
||||||
case .Big: return ODIN_ENDIAN != "big"
|
case .Big: return ODIN_ENDIAN != .Big
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -329,3 +392,116 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write key as quoted string or with optional quotes in mjson
|
||||||
|
opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) {
|
||||||
|
switch opt.spec {
|
||||||
|
case .JSON, .JSON5:
|
||||||
|
io.write_quoted_string(w, name) or_return
|
||||||
|
io.write_string(w, ": ") or_return
|
||||||
|
|
||||||
|
case .MJSON:
|
||||||
|
if opt.mjson_keys_use_quotes {
|
||||||
|
io.write_quoted_string(w, name) or_return
|
||||||
|
} else {
|
||||||
|
io.write_string(w, name) or_return
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.mjson_keys_use_equal_sign {
|
||||||
|
io.write_string(w, " = ") or_return
|
||||||
|
} else {
|
||||||
|
io.write_string(w, ": ") or_return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert start byte and increase indentation on pretty
|
||||||
|
opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
|
||||||
|
// skip mjson starting braces
|
||||||
|
if opt.spec == .MJSON && !opt.mjson_skipped_first_braces_start {
|
||||||
|
opt.mjson_skipped_first_braces_start = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
io.write_byte(w, c) or_return
|
||||||
|
opt.indentation += 1
|
||||||
|
|
||||||
|
if opt.pretty {
|
||||||
|
io.write_byte(w, '\n') or_return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert comma seperation and write indentations
|
||||||
|
opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) {
|
||||||
|
switch opt.spec {
|
||||||
|
case .JSON, .JSON5:
|
||||||
|
if iteration > 0 {
|
||||||
|
io.write_string(w, ", ") or_return
|
||||||
|
|
||||||
|
if opt.pretty {
|
||||||
|
io.write_byte(w, '\n') or_return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opt_write_indentation(w, opt) or_return
|
||||||
|
|
||||||
|
case .MJSON:
|
||||||
|
if iteration > 0 {
|
||||||
|
// on pretty no commas necessary
|
||||||
|
if opt.pretty {
|
||||||
|
io.write_byte(w, '\n') or_return
|
||||||
|
} else {
|
||||||
|
// comma seperation necessary for non pretty output!
|
||||||
|
io.write_string(w, ", ") or_return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opt_write_indentation(w, opt) or_return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrease indent, write spacing and insert end byte
|
||||||
|
opt_write_end :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
|
||||||
|
if opt.spec == .MJSON && opt.mjson_skipped_first_braces_start && !opt.mjson_skipped_first_braces_end {
|
||||||
|
if opt.indentation == 0 {
|
||||||
|
opt.mjson_skipped_first_braces_end = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.indentation -= 1
|
||||||
|
|
||||||
|
if opt.pretty {
|
||||||
|
io.write_byte(w, '\n') or_return
|
||||||
|
opt_write_indentation(w, opt) or_return
|
||||||
|
}
|
||||||
|
|
||||||
|
io.write_byte(w, c) or_return
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes current indentation level based on options
|
||||||
|
opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.Error) {
|
||||||
|
if !opt.pretty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.use_spaces {
|
||||||
|
spaces := opt.spaces == 0 ? 4 : opt.spaces
|
||||||
|
for _ in 0..<opt.indentation * spaces {
|
||||||
|
io.write_byte(w, ' ') or_return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _ in 0..<opt.indentation {
|
||||||
|
io.write_byte(w, '\t') or_return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers
|
|||||||
return parse_object(&p)
|
return parse_object(&p)
|
||||||
case .JSON5:
|
case .JSON5:
|
||||||
return parse_value(&p)
|
return parse_value(&p)
|
||||||
case .MJSON:
|
case .SJSON:
|
||||||
#partial switch p.curr_token.kind {
|
#partial switch p.curr_token.kind {
|
||||||
case .Ident, .String:
|
case .Ident, .String:
|
||||||
return parse_object_body(&p, .EOF)
|
return parse_object_body(&p, .EOF)
|
||||||
@@ -354,6 +354,12 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
|
|||||||
|
|
||||||
b := bytes_make(len(s) + 2*utf8.UTF_MAX, 1, allocator) or_return
|
b := bytes_make(len(s) + 2*utf8.UTF_MAX, 1, allocator) or_return
|
||||||
w := copy(b, s[0:i])
|
w := copy(b, s[0:i])
|
||||||
|
|
||||||
|
if len(b) == 0 && allocator.data == nil {
|
||||||
|
// `unmarshal_count_array` calls us with a nil allocator
|
||||||
|
return string(b[:w]), nil
|
||||||
|
}
|
||||||
|
|
||||||
loop: for i < len(s) {
|
loop: for i < len(s) {
|
||||||
c := s[i]
|
c := s[i]
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ package json
|
|||||||
Specification :: enum {
|
Specification :: enum {
|
||||||
JSON,
|
JSON,
|
||||||
JSON5, // https://json5.org/
|
JSON5, // https://json5.org/
|
||||||
MJSON, // https://bitsquid.blogspot.com/2009/10/simplified-json-notation.html
|
SJSON, // https://bitsquid.blogspot.com/2009/10/simplified-json-notation.html
|
||||||
Bitsquid = MJSON,
|
Bitsquid = SJSON,
|
||||||
|
MJSON = SJSON,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
|||||||
variant := u.variants[0]
|
variant := u.variants[0]
|
||||||
v.id = variant.id
|
v.id = variant.id
|
||||||
ti = reflect.type_info_base(variant)
|
ti = reflect.type_info_base(variant)
|
||||||
if !(u.maybe && reflect.is_pointer(variant)) {
|
if !reflect.is_pointer_internally(variant) {
|
||||||
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||||
assign_int(tag, 1)
|
assign_int(tag, 1)
|
||||||
}
|
}
|
||||||
@@ -325,7 +325,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
|
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
|
||||||
|
|
||||||
if end_token == .Close_Brace {
|
if end_token == .Close_Brace {
|
||||||
assert(expect_token(p, .Open_Brace) == nil)
|
unmarshal_expect_token(p, .Open_Brace)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := v
|
v := v
|
||||||
@@ -473,7 +473,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
}
|
}
|
||||||
|
|
||||||
if end_token == .Close_Brace {
|
if end_token == .Close_Brace {
|
||||||
assert(expect_token(p, .Close_Brace) == nil)
|
unmarshal_expect_token(p, .Close_Brace)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
|
||||||
|
|
||||||
|
Author of this Odin package: Jeroen van Rijn
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```odin
|
||||||
|
import "core:encoding/varint"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
buf: [varint.LEB128_MAX_BYTES]u8
|
||||||
|
|
||||||
|
value := u128(42)
|
||||||
|
|
||||||
|
encode_size, encode_err := varint.encode_uleb128(buf[:], value)
|
||||||
|
assert(encode_size == 1 && encode_err == .None)
|
||||||
|
|
||||||
|
fmt.printf("Encoded as %v\n", buf[:encode_size])
|
||||||
|
decoded_val, decode_size, decode_err := varint.decode_uleb128(buf[:])
|
||||||
|
|
||||||
|
assert(decoded_val == value && decode_size == encode_size && decode_err == .None)
|
||||||
|
fmt.printf("Decoded as %v, using %v byte%v\n", decoded_val, decode_size, "" if decode_size == 1 else "s")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*/
|
||||||
|
package varint
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-3 license.
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
Jeroen van Rijn: Initial implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package varint implements variable length integer encoding and decoding using
|
||||||
|
// the LEB128 format as used by DWARF debug info, Android .dex and other file formats.
|
||||||
|
package varint
|
||||||
|
|
||||||
|
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
|
||||||
|
// Instead we'll set limits on the values we'll encode/decode
|
||||||
|
// 18 * 7 bits = 126, which means that a possible 19th byte may at most be `0b0000_0011`.
|
||||||
|
LEB128_MAX_BYTES :: 19
|
||||||
|
|
||||||
|
Error :: enum {
|
||||||
|
None = 0,
|
||||||
|
Buffer_Too_Small = 1,
|
||||||
|
Value_Too_Large = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used.
|
||||||
|
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
|
||||||
|
decode_uleb128_buffer :: proc(buf: []u8) -> (val: u128, size: int, err: Error) {
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in buf {
|
||||||
|
val, size, err = decode_uleb128_byte(v, size, val)
|
||||||
|
if err != .Buffer_Too_Small {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == .Buffer_Too_Small {
|
||||||
|
val, size = 0, 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decodes an unsigned LEB128 integer into value a byte at a time.
|
||||||
|
// Returns `.None` when decoded properly, `.Value_Too_Large` when they value
|
||||||
|
// exceeds the limits of a u128, and `.Buffer_Too_Small` when it's not yet fully decoded.
|
||||||
|
decode_uleb128_byte :: proc(input: u8, offset: int, accumulator: u128) -> (val: u128, size: int, err: Error) {
|
||||||
|
size = offset + 1
|
||||||
|
|
||||||
|
// 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011.
|
||||||
|
if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && input > 0b0000_0011 {
|
||||||
|
return 0, 0, .Value_Too_Large
|
||||||
|
}
|
||||||
|
|
||||||
|
val = accumulator | u128(input & 0x7f) << uint(offset * 7)
|
||||||
|
|
||||||
|
if input < 128 {
|
||||||
|
// We're done
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the buffer runs out before the number ends, return an error.
|
||||||
|
return val, size, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
decode_uleb128 :: proc {decode_uleb128_buffer, decode_uleb128_byte}
|
||||||
|
|
||||||
|
// Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used.
|
||||||
|
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
|
||||||
|
decode_ileb128_buffer :: proc(buf: []u8) -> (val: i128, size: int, err: Error) {
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in buf {
|
||||||
|
val, size, err = decode_ileb128_byte(v, size, val)
|
||||||
|
if err != .Buffer_Too_Small {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == .Buffer_Too_Small {
|
||||||
|
val, size = 0, 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a a signed LEB128 integer into value and number of bytes used, one byte at a time.
|
||||||
|
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
|
||||||
|
decode_ileb128_byte :: proc(input: u8, offset: int, accumulator: i128) -> (val: i128, size: int, err: Error) {
|
||||||
|
size = offset + 1
|
||||||
|
shift := uint(offset * 7)
|
||||||
|
|
||||||
|
// 18 * 7 bits = 126, which including sign means we can have a 19th byte.
|
||||||
|
if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && input > 0x7f {
|
||||||
|
return 0, 0, .Value_Too_Large
|
||||||
|
}
|
||||||
|
|
||||||
|
val = accumulator | i128(input & 0x7f) << shift
|
||||||
|
|
||||||
|
if input < 128 {
|
||||||
|
if input & 0x40 == 0x40 {
|
||||||
|
val |= max(i128) << (shift + 7)
|
||||||
|
}
|
||||||
|
return val, size, .None
|
||||||
|
}
|
||||||
|
return val, size, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
decode_ileb128 :: proc{decode_ileb128_buffer, decode_ileb128_byte}
|
||||||
|
|
||||||
|
// Encode `val` into `buf` as an unsigned LEB128 encoded series of bytes.
|
||||||
|
// `buf` must be appropriately sized.
|
||||||
|
encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) {
|
||||||
|
val := val
|
||||||
|
|
||||||
|
for {
|
||||||
|
size += 1
|
||||||
|
|
||||||
|
if size > len(buf) {
|
||||||
|
return 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
low := val & 0x7f
|
||||||
|
val >>= 7
|
||||||
|
|
||||||
|
if val > 0 {
|
||||||
|
low |= 0x80 // more bytes to follow
|
||||||
|
}
|
||||||
|
buf[size - 1] = u8(low)
|
||||||
|
|
||||||
|
if val == 0 { break }
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode `val` into `buf` as a signed LEB128 encoded series of bytes.
|
||||||
|
// `buf` must be appropriately sized.
|
||||||
|
encode_ileb128 :: proc(buf: []u8, val: i128) -> (size: int, err: Error) {
|
||||||
|
SIGN_MASK :: i128(1) << 121 // sign extend mask
|
||||||
|
|
||||||
|
val, more := val, true
|
||||||
|
|
||||||
|
for more {
|
||||||
|
size += 1
|
||||||
|
|
||||||
|
if size > len(buf) {
|
||||||
|
return 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
low := val & 0x7f
|
||||||
|
val >>= 7
|
||||||
|
|
||||||
|
low = (low ~ SIGN_MASK) - SIGN_MASK
|
||||||
|
|
||||||
|
if (val == 0 && low & 0x40 != 0x40) || (val == -1 && low & 0x40 == 0x40) {
|
||||||
|
more = false
|
||||||
|
} else {
|
||||||
|
low |= 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[size - 1] = u8(low)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
An XML 1.0 / 1.1 parser
|
||||||
|
|
||||||
|
Copyright 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-3 license.
|
||||||
|
|
||||||
|
A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
Jeroen van Rijn: Initial implementation.
|
||||||
|
*/
|
||||||
|
package xml
|
||||||
|
|
||||||
|
import "core:io"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Just for debug purposes.
|
||||||
|
*/
|
||||||
|
print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error) {
|
||||||
|
if doc == nil { return }
|
||||||
|
using fmt
|
||||||
|
|
||||||
|
written += wprintf(writer, "[XML Prolog]\n")
|
||||||
|
|
||||||
|
for attr in doc.prologue {
|
||||||
|
written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
written += wprintf(writer, "[Encoding] %v\n", doc.encoding)
|
||||||
|
|
||||||
|
if len(doc.doctype.ident) > 0 {
|
||||||
|
written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident)
|
||||||
|
|
||||||
|
if len(doc.doctype.rest) > 0 {
|
||||||
|
wprintf(writer, "\t%v\n", doc.doctype.rest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for comment in doc.comments {
|
||||||
|
written += wprintf(writer, "[Pre-root comment] %v\n", comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(doc.elements) > 0 {
|
||||||
|
wprintln(writer, " --- ")
|
||||||
|
print_element(writer, doc, 0)
|
||||||
|
wprintln(writer, " --- ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return written, .None
|
||||||
|
}
|
||||||
|
|
||||||
|
print_element :: proc(writer: io.Writer, doc: ^Document, element_id: Element_ID, indent := 0) -> (written: int, err: io.Error) {
|
||||||
|
using fmt
|
||||||
|
|
||||||
|
tab :: proc(writer: io.Writer, indent: int) {
|
||||||
|
for _ in 0..=indent {
|
||||||
|
wprintf(writer, "\t")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tab(writer, indent)
|
||||||
|
|
||||||
|
element := doc.elements[element_id]
|
||||||
|
|
||||||
|
if element.kind == .Element {
|
||||||
|
wprintf(writer, "<%v>\n", element.ident)
|
||||||
|
if len(element.value) > 0 {
|
||||||
|
tab(writer, indent + 1)
|
||||||
|
wprintf(writer, "[Value] %v\n", element.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in element.attribs {
|
||||||
|
tab(writer, indent + 1)
|
||||||
|
wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
for child in element.children {
|
||||||
|
print_element(writer, doc, child, indent + 1)
|
||||||
|
}
|
||||||
|
} else if element.kind == .Comment {
|
||||||
|
wprintf(writer, "[COMMENT] %v\n", element.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return written, .None
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package xml_example
|
||||||
|
|
||||||
|
import "core:encoding/xml"
|
||||||
|
import "core:mem"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:time"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:hash"
|
||||||
|
|
||||||
|
N :: 1
|
||||||
|
|
||||||
|
example :: proc() {
|
||||||
|
using fmt
|
||||||
|
|
||||||
|
docs: [N]^xml.Document
|
||||||
|
errs: [N]xml.Error
|
||||||
|
times: [N]time.Duration
|
||||||
|
|
||||||
|
defer for round in 0..<N {
|
||||||
|
xml.destroy(docs[round])
|
||||||
|
}
|
||||||
|
|
||||||
|
DOC :: #load("../../../../tests/core/assets/XML/unicode.xml")
|
||||||
|
input := DOC
|
||||||
|
|
||||||
|
for round in 0..<N {
|
||||||
|
start := time.tick_now()
|
||||||
|
|
||||||
|
docs[round], errs[round] = xml.parse(input, xml.Options{
|
||||||
|
flags={.Ignore_Unsupported},
|
||||||
|
expected_doctype = "",
|
||||||
|
})
|
||||||
|
|
||||||
|
end := time.tick_now()
|
||||||
|
times[round] = time.tick_diff(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
fastest := max(time.Duration)
|
||||||
|
slowest := time.Duration(0)
|
||||||
|
total := time.Duration(0)
|
||||||
|
|
||||||
|
for round in 0..<N {
|
||||||
|
fastest = min(fastest, times[round])
|
||||||
|
slowest = max(slowest, times[round])
|
||||||
|
total += times[round]
|
||||||
|
}
|
||||||
|
|
||||||
|
fastest_ms := time.duration_milliseconds(fastest)
|
||||||
|
slowest_ms := time.duration_milliseconds(slowest)
|
||||||
|
average_ms := time.duration_milliseconds(time.Duration(f64(total) / f64(N)))
|
||||||
|
|
||||||
|
fastest_speed := (f64(1000.0) / fastest_ms) * f64(len(DOC)) / 1_024.0 / 1_024.0
|
||||||
|
slowest_speed := (f64(1000.0) / slowest_ms) * f64(len(DOC)) / 1_024.0 / 1_024.0
|
||||||
|
average_speed := (f64(1000.0) / average_ms) * f64(len(DOC)) / 1_024.0 / 1_024.0
|
||||||
|
|
||||||
|
fmt.printf("N = %v\n", N)
|
||||||
|
fmt.printf("[Fastest]: %v bytes in %.2f ms (%.2f MiB/s).\n", len(input), fastest_ms, fastest_speed)
|
||||||
|
fmt.printf("[Slowest]: %v bytes in %.2f ms (%.2f MiB/s).\n", len(input), slowest_ms, slowest_speed)
|
||||||
|
fmt.printf("[Average]: %v bytes in %.2f ms (%.2f MiB/s).\n", len(input), average_ms, average_speed)
|
||||||
|
|
||||||
|
if errs[0] != .None {
|
||||||
|
printf("Load/Parse error: %v\n", errs[0])
|
||||||
|
if errs[0] == .File_Error {
|
||||||
|
println("\"unicode.xml\" not found. Did you run \"tests\\download_assets.py\"?")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
charlist, charlist_ok := xml.find_child_by_ident(docs[0], 0, "charlist")
|
||||||
|
if !charlist_ok {
|
||||||
|
eprintln("Could not locate top-level `<charlist>` tag.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Found `<charlist>` with %v children, %v elements total\n", len(docs[0].elements[charlist].children), docs[0].element_count)
|
||||||
|
|
||||||
|
crc32 := doc_hash(docs[0])
|
||||||
|
printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0xcaa042b9 else "🤬", crc32)
|
||||||
|
|
||||||
|
for round in 0..<N {
|
||||||
|
defer xml.destroy(docs[round])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) {
|
||||||
|
buf: strings.Builder
|
||||||
|
defer strings.builder_destroy(&buf)
|
||||||
|
w := strings.to_writer(&buf)
|
||||||
|
|
||||||
|
xml.print(w, doc)
|
||||||
|
tree := strings.to_string(buf)
|
||||||
|
if print { fmt.println(tree) }
|
||||||
|
return hash.crc32(transmute([]u8)tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
using fmt
|
||||||
|
|
||||||
|
track: mem.Tracking_Allocator
|
||||||
|
mem.tracking_allocator_init(&track, context.allocator)
|
||||||
|
context.allocator = mem.tracking_allocator(&track)
|
||||||
|
|
||||||
|
example()
|
||||||
|
|
||||||
|
if len(track.allocation_map) > 0 {
|
||||||
|
println()
|
||||||
|
for _, v in track.allocation_map {
|
||||||
|
printf("%v Leaked %v bytes.\n", v.location, v.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("Done and cleaned up!")
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
An XML 1.0 / 1.1 parser
|
||||||
|
|
||||||
|
Copyright 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-3 license.
|
||||||
|
|
||||||
|
This file contains helper functions.
|
||||||
|
*/
|
||||||
|
package xml
|
||||||
|
|
||||||
|
// Find parent's nth child with a given ident.
|
||||||
|
find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string, nth := 0) -> (res: Element_ID, found: bool) {
|
||||||
|
tag := doc.elements[parent_id]
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for child_id in tag.children {
|
||||||
|
child := doc.elements[child_id]
|
||||||
|
/*
|
||||||
|
Skip commments. They have no name.
|
||||||
|
*/
|
||||||
|
if child.kind != .Element { continue }
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the ident matches and it's the nth such child, return it.
|
||||||
|
*/
|
||||||
|
if child.ident == ident {
|
||||||
|
if count == nth { return child_id, true }
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find an attribute by key.
|
||||||
|
find_attribute_val_by_key :: proc(doc: ^Document, parent_id: Element_ID, key: string) -> (val: string, found: bool) {
|
||||||
|
tag := doc.elements[parent_id]
|
||||||
|
|
||||||
|
for attr in tag.attribs {
|
||||||
|
/*
|
||||||
|
If the ident matches, we're done. There can only ever be one attribute with the same name.
|
||||||
|
*/
|
||||||
|
if attr.key == key { return attr.val, true }
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user