mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 19:21:37 -07:00
Compare commits
1890 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 539cec7496 | |||
| 000709b594 | |||
| c51f94b600 | |||
| b703d5ca58 | |||
| aff345f57f | |||
| a4664f82cc | |||
| 9fb090d1b8 | |||
| 4a2ad3b13a | |||
| 9d5afee24b | |||
| 6736205723 | |||
| f0a7f1812f | |||
| 9c9ae5987a | |||
| f588593ff1 | |||
| a626adac8e | |||
| 338793b68e | |||
| 59575d9b22 | |||
| b58a0b60d0 | |||
| 3a4c82abf8 | |||
| 946cf52df1 | |||
| a78f062499 | |||
| 3c47503780 | |||
| 6da82e038d | |||
| 38af752cd1 | |||
| 0428f508d8 | |||
| 3c24584290 | |||
| 535b8a9483 | |||
| 038086d1d9 | |||
| 9a16bc5fc5 | |||
| eee8e0faa2 | |||
| 3e7e779abf | |||
| 6a07effdd2 | |||
| 395e0fb225 | |||
| 9be9f0bb2c | |||
| 9e7cc8cf93 | |||
| 2743bf7e44 | |||
| d95c28f41b | |||
| e57224d6e4 | |||
| f67691c457 | |||
| d04c82e547 | |||
| 09fa1c29cd | |||
| ddcaa0de53 | |||
| 621b3c7829 | |||
| 68df35b378 | |||
| c1d853a24e | |||
| 30636f5114 | |||
| 31914e9cb9 | |||
| da6edb3764 | |||
| 9a9625f885 | |||
| 15b40a4f29 | |||
| 5406acc8fa | |||
| d5b0ec712b | |||
| 766d6aa946 | |||
| 895ebb95d5 | |||
| af636eedde | |||
| 57b7822e12 | |||
| 03736d8bcb | |||
| 3a5d80b291 | |||
| 967ccfc7cc | |||
| 712ae1c5ac | |||
| 9cfd4a953e | |||
| 14e2cc17d6 | |||
| 5f41741e8c | |||
| 8a067bc1fc | |||
| cfdf2bfb77 | |||
| 2f8316840e | |||
| a660098106 | |||
| 90d1f9ab27 | |||
| 2097b09abb | |||
| f63f28302e | |||
| 98b539ac5c | |||
| 9d067ae562 | |||
| 5a542c7ad5 | |||
| 73f57c5933 | |||
| 2071d7ba84 | |||
| e8102a40d0 | |||
| 737677f1b6 | |||
| fc047a8043 | |||
| ae52e245ea | |||
| b8bfc715bf | |||
| b0aa08f85b | |||
| d6ee5e89fa | |||
| a263da0bbe | |||
| 9cb02aa51d | |||
| 799f4379d8 | |||
| bd51b21386 | |||
| 276284cbec | |||
| a8021f03a6 | |||
| c35d5d4c42 | |||
| 248a0bfa5f | |||
| 34791707fd | |||
| 37ae9eb609 | |||
| b6838731f5 | |||
| 991c1d4446 | |||
| d0bb1fb844 | |||
| ea43c030aa | |||
| d54f34a162 | |||
| a86cfa6e97 | |||
| 1b83f4a18b | |||
| 90ac400ec5 | |||
| 75c659fa41 | |||
| 8cfff254c9 | |||
| 8c2eb5df78 | |||
| a2f0ac0fd2 | |||
| 2987fc65a1 | |||
| c5bab58180 | |||
| 5ad88ea169 | |||
| 72d6b9b683 | |||
| 2f2c086382 | |||
| d9fafa7000 | |||
| 12e53f2336 | |||
| a2e729c303 | |||
| 7b89174a26 | |||
| 1d7f7a55d2 | |||
| 766485ccab | |||
| 6642aa94d5 | |||
| 1c9ec27d36 | |||
| 05e27fa92d | |||
| 7954a7a6f3 | |||
| 1d621295b1 | |||
| 02c2aff41b | |||
| 5476d43441 | |||
| b25e85a8bb | |||
| 190103883c | |||
| d460dd2bdc | |||
| 7ee7f4b064 | |||
| f2d3376c0b | |||
| 0fcd2f1d88 | |||
| 76f52dd6c9 | |||
| ae0be9c785 | |||
| 3f6f00d8e5 | |||
| c58eeca1b2 | |||
| 5032839abc | |||
| 2b1d85968d | |||
| 5896469f3b | |||
| 70c150fc83 | |||
| 2411febf83 | |||
| 5e7b031a1d | |||
| ef05e0858d | |||
| 880a18f124 | |||
| 5d94887e76 | |||
| 577049c69e | |||
| 46f46e645c | |||
| b13aa5db37 | |||
| 2990747cf8 | |||
| 62c30795e6 | |||
| bb94f4d129 | |||
| 7b53dbeb8a | |||
| 120ef168bf | |||
| 72dfb73c9d | |||
| 67dcd916e8 | |||
| 7f6f971284 | |||
| 67d5b97ff9 | |||
| efb2b05040 | |||
| 656e62d724 | |||
| ce8801c37f | |||
| c6c710465a | |||
| f3dc1f6e3b | |||
| 873b7f8588 | |||
| 7d3dfb1046 | |||
| f4782157d3 | |||
| 8de7d2f18f | |||
| aff8f06e3c | |||
| 0bf1b6c2f1 | |||
| 2017ebc1b5 | |||
| da56a75ad6 | |||
| 1e1228fb37 | |||
| 8d7c37e384 | |||
| cd65a15d81 | |||
| 9235e82451 | |||
| ecee0e2db2 | |||
| 0580eebd2a | |||
| 909a5016ee | |||
| c2c89e54a5 | |||
| 6389d9c11f | |||
| 2784e8ea51 | |||
| 85b71708dd | |||
| 649b5fa528 | |||
| d6a89d667d | |||
| b408ec6bac | |||
| 8545f316ff | |||
| 3bf7b416e7 | |||
| 0b83e3dae5 | |||
| d7d23e65ea | |||
| 2820bbc269 | |||
| 70c5153471 | |||
| 5961d4b316 | |||
| b59c80d6fd | |||
| 8c10f4cdde | |||
| 0cc72b536f | |||
| 8a7c2ea9d0 | |||
| cb1c10ce83 | |||
| 37c2e9bec3 | |||
| 4626cd03da | |||
| 3850be2e11 | |||
| 4c9aa30a1e | |||
| da977cf1e6 | |||
| ee97c5958f | |||
| 778bbee17c | |||
| 4efef08c94 | |||
| 87c835268a | |||
| 83ed0b37cd | |||
| dc49cf766f | |||
| 933754193a | |||
| 76eef47491 | |||
| 0e21f45076 | |||
| 9bfe3a94f4 | |||
| a2009220a2 | |||
| b410383aaf | |||
| b47736260a | |||
| 5154bb551a | |||
| 89084befb0 | |||
| f3caa4aee3 | |||
| 3ec253f385 | |||
| 759e342872 | |||
| 120b1101fb | |||
| 252fd0e928 | |||
| 1fa2af213d | |||
| de84db85cb | |||
| 33d85adf34 | |||
| 383d485e2a | |||
| 68d2b7bb89 | |||
| d667809e0a | |||
| 64ed4389ff | |||
| 4701b31b55 | |||
| e52cc73d50 | |||
| ac0ed13b35 | |||
| 269957b9fb | |||
| 464a675adc | |||
| 55f3e99f63 | |||
| 49fb0acfc9 | |||
| 09db245e4c | |||
| bc7972fbaf | |||
| 6f80d2dc36 | |||
| 46250168d6 | |||
| 509712f771 | |||
| 4b38dbe133 | |||
| ad0ffa4833 | |||
| b89fc9191c | |||
| 829e4cc67e | |||
| beb4699b46 | |||
| 031b0cc534 | |||
| ee504aa596 | |||
| baa5ea9258 | |||
| 9a490e4e0d | |||
| 252de70b0f | |||
| 4ae021cd4c | |||
| af962526df | |||
| 6024af172c | |||
| 8bd5a9bb9e | |||
| a9166f52f8 | |||
| 9bdd4c73a5 | |||
| 2362be11bf | |||
| 5b8a76c583 | |||
| 2a0e4f7a8c | |||
| ece82eecc3 | |||
| 67d02043fe | |||
| 29c80c238d | |||
| a4606e4da8 | |||
| d4df3f6383 | |||
| 58ff3dd1ed | |||
| cf8c9a6be4 | |||
| ea709451e8 | |||
| d47a403d29 | |||
| 1606f756b3 | |||
| 2e9298891e | |||
| f8b85339af | |||
| 12b8f91249 | |||
| 8e395cc6e9 | |||
| feba52002e | |||
| ca2b2c498e | |||
| 6e9e469abd | |||
| 0490ba46f4 | |||
| e0652ee2f4 | |||
| bc99bacb21 | |||
| 173527d631 | |||
| f8cb2bcad2 | |||
| b011487778 | |||
| c8cc130744 | |||
| fe0244606b | |||
| 036fa6482c | |||
| 04ca22b9ea | |||
| bf9ae77fbd | |||
| 4adfc120ba | |||
| d8bb93accc | |||
| e410908ce8 | |||
| d278c852cc | |||
| 364b64718f | |||
| 61335089c6 | |||
| 040b90ce76 | |||
| 843b2350eb | |||
| 526d338300 | |||
| a6aca5d6d1 | |||
| 05c67c3243 | |||
| 31b1aef44e | |||
| a8c09d77ff | |||
| 5665ae02bc | |||
| 92d3a681cd | |||
| cb66ed52ce | |||
| 2e1b2dc3ba | |||
| 65333181fc | |||
| 30ad923558 | |||
| a31ab31e96 | |||
| ac760a0bdd | |||
| fbf0180411 | |||
| 198ac00994 | |||
| 603764dbca | |||
| cb04333480 | |||
| 0e169fd1c2 | |||
| 68cf51c8f8 | |||
| 65afe6f70d | |||
| 291a064725 | |||
| bfbeb23f54 | |||
| 58e4a011c7 | |||
| 3de15987bd | |||
| c5c46c5073 | |||
| abe896a7be | |||
| f00df0afe9 | |||
| 35f21abc7b | |||
| b1977dfa4b | |||
| e23eba0914 | |||
| 4b245e2d83 | |||
| f169d8c396 | |||
| 39f8437f4d | |||
| 4aa8834d39 | |||
| f79efd43e4 | |||
| 058132e7e6 | |||
| 9b7c5f2b1b | |||
| 06e61c7315 | |||
| 1b23dbb228 | |||
| cc2ba146a6 | |||
| 3bbdc93882 | |||
| 0091193c04 | |||
| 1b5bcc1a99 | |||
| 5a661dc67b | |||
| fb48131f3c | |||
| 9300c99d65 | |||
| 9366bf44a6 | |||
| e8e3501443 | |||
| 9f96382558 | |||
| 82088e4a75 | |||
| b12bfe407d | |||
| 1e726bb3e0 | |||
| 1db5e1250f | |||
| e0ecae66fd | |||
| 0df7fe4247 | |||
| 84a8e17482 | |||
| cabaac5a68 | |||
| 2bb5c4cafc | |||
| bfff322eb9 | |||
| dd60802db4 | |||
| 6db42cfaec | |||
| 21f5b41150 | |||
| 1f007a46ee | |||
| 4fa4feb669 | |||
| 5fd3fc4c7c | |||
| ee2d3e00fd | |||
| 6f65ed6cc8 | |||
| 70525a12ca | |||
| 914950592c | |||
| 3c021f9c52 | |||
| 9ea88f1353 | |||
| 4d89249caf | |||
| ff0e976ff3 | |||
| 0df1645422 | |||
| bb6d73953c | |||
| c9c14bab8a | |||
| 7c6117bb8f | |||
| ae40946198 | |||
| 8063569cdd | |||
| dab72d5615 | |||
| 89493b70a9 | |||
| c12eb3ec93 | |||
| 7343ed0cac | |||
| 3102abf1aa | |||
| 03282c1234 | |||
| 490c8daedd | |||
| e78ee90ac2 | |||
| f809788f75 | |||
| 0888c69b57 | |||
| ab39644156 | |||
| 4c1a9d2b3f | |||
| f6308ab5b9 | |||
| 3baf8d92c3 | |||
| 34065865a0 | |||
| 3d90e580c5 | |||
| f635d3d8af | |||
| 29f1b79d70 | |||
| 955be66f1a | |||
| a0e6ae6f33 | |||
| 08d032859f | |||
| 4af77aeff6 | |||
| 6749639eb1 | |||
| 8a56bb3b5f | |||
| 37e79f9cca | |||
| a4c64002c5 | |||
| 63b6e8216c | |||
| 3e7b5670fb | |||
| e2e18324ed | |||
| 924039c01b | |||
| 2af2a035dc | |||
| f97ccca514 | |||
| 25e9255157 | |||
| 2e64866838 | |||
| b21b5ef222 | |||
| d9fab5e824 | |||
| 0424404140 | |||
| db89c2ccd0 | |||
| 0c97f6aa4e | |||
| af78ad2a87 | |||
| 9cc5cd9d40 | |||
| 59950bcad6 | |||
| 4587a55486 | |||
| 7640fb0483 | |||
| b8f9deb3d8 | |||
| 92aad90c6b | |||
| 506adfb105 | |||
| e819eebc63 | |||
| 841e73fcd5 | |||
| aa821991b8 | |||
| b71afdc3ee | |||
| bc139ba6c6 | |||
| 8af6da5de1 | |||
| 0b86038482 | |||
| 8d943f5902 | |||
| 32b27c690d | |||
| 3494a6dcd8 | |||
| 235fec23af | |||
| 97b066f112 | |||
| a99c0b3e4a | |||
| 2a6fb3a387 | |||
| 65204f13a8 | |||
| 8438d66e6b | |||
| 44c8da7bf2 | |||
| 41fdcfeecf | |||
| 70ba4b5321 | |||
| 71da3ef925 | |||
| 582bd760b7 | |||
| e86bb3a795 | |||
| e3a836f93c | |||
| 31b42a53fc | |||
| b71d3c739a | |||
| a162b51588 | |||
| 7c1119f217 | |||
| b0397581db | |||
| c7dc1220b3 | |||
| d16acdc89c | |||
| 1279ebe948 | |||
| aa5a95a4d1 | |||
| fa1cb28c8f | |||
| 3902273d68 | |||
| 811132ccbd | |||
| 391b3090c9 | |||
| d50380709d | |||
| 14a46c6d5e | |||
| b4e3da84c5 | |||
| 9d627e453a | |||
| d6e0e5d3f6 | |||
| 12b370ddc1 | |||
| 50f86dc14f | |||
| 9078ddaf5a | |||
| 8028033513 | |||
| 6b9202dfbf | |||
| 04c928fb9e | |||
| 354d00963c | |||
| 9e5e49a65d | |||
| 8a849bd1bd | |||
| 1b3fb11a31 | |||
| b30ceab864 | |||
| 3e1791aa5c | |||
| 2cb5cc774d | |||
| 5f7843a13d | |||
| 1b770fc3b2 | |||
| 79d3c3be66 | |||
| 55d42492ac | |||
| 9737c2ad0b | |||
| b9a813a69d | |||
| e0ac454ed0 | |||
| 1db95aa09d | |||
| c0bbe1e23d | |||
| 9e35361eb8 | |||
| cce42f4a6b | |||
| bd19081543 | |||
| dd9b0ae4e5 | |||
| 3b5d28f0ee | |||
| 0ca39c70a5 | |||
| 270348b112 | |||
| e67473d89a | |||
| 086478e8f2 | |||
| 5a8da5dcdb | |||
| f6f4734fee | |||
| f903951016 | |||
| e19460cbd7 | |||
| 6de2b7700f | |||
| 4e145cf69c | |||
| 341087a82b | |||
| 851fd1f8d1 | |||
| ce43b04688 | |||
| ff1ab74b3c | |||
| aed67ba665 | |||
| 70c1f9d0e1 | |||
| 761a079789 | |||
| 4116d66c59 | |||
| fc6edf65d7 | |||
| 548ab2e1b6 | |||
| 13a3c0e57c | |||
| 9834ceed42 | |||
| 4266a7c166 | |||
| 639cc9faa8 | |||
| e2cecafa66 | |||
| 4bcb68a973 | |||
| 7131772754 | |||
| c2e5602ee5 | |||
| 8714fd77a0 | |||
| c20839c461 | |||
| 51229a29f8 | |||
| 59675949da | |||
| 6564ce0fb0 | |||
| c36ac4bdfd | |||
| 764ce2a4b0 | |||
| d400a5a108 | |||
| 744eb7c6d8 | |||
| 1b79e2ca5f | |||
| 4cb0edc90b | |||
| 6201280468 | |||
| 9e36e28217 | |||
| 5edb2c5688 | |||
| ce5e7998ba | |||
| 4a4aca6829 | |||
| f26ed39e86 | |||
| 574d2baf09 | |||
| 1e622979f8 | |||
| 1f969fdc75 | |||
| e206d6ba35 | |||
| 7faa146004 | |||
| ef5eb4b612 | |||
| 864b29f7f1 | |||
| 4d498b668a | |||
| 75cb2c68cc | |||
| 942e91f94c | |||
| d8f06ed557 | |||
| a73ff00b02 | |||
| a58a08c0c3 | |||
| 62d0b0ae72 | |||
| 2c9ef2e1bc | |||
| 9b68671082 | |||
| 5c533e477d | |||
| 03ab6add5c | |||
| 052633b73c | |||
| bf9a8032a1 | |||
| eb261f5b28 | |||
| f5febb633c | |||
| d2ac3c2228 | |||
| 51caa930ca | |||
| b7af4e7f6b | |||
| 82cd30a145 | |||
| 8caae16113 | |||
| dc789c43b6 | |||
| 2e73fb25af | |||
| 1577d60d02 | |||
| 3bd1918c5e | |||
| 263b3141b5 | |||
| 82263a8b38 | |||
| 61ad2a1345 | |||
| d589914956 | |||
| f54a026acc | |||
| fc06d7011d | |||
| ed7c9ec619 | |||
| 1d9f6346d4 | |||
| a3a3156ddd | |||
| 70bd4a5ab6 | |||
| 21247721b4 | |||
| 4436d24440 | |||
| 7a16618ec6 | |||
| 2b2abc6b9f | |||
| 034aead930 | |||
| c8a5bafc6b | |||
| 0a7b9338f6 | |||
| bc0fa1240b | |||
| 292398dbe2 | |||
| 49da19e013 | |||
| 056840975f | |||
| 160b23f991 | |||
| bbd4c1054e | |||
| 152ac61faf | |||
| 4d65b1ab9c | |||
| 8b2f62000a | |||
| 166803a2a5 | |||
| 11a2b2a942 | |||
| 0a492acaa1 | |||
| e86d7f1fb0 | |||
| 962d599996 | |||
| ba536d67b4 | |||
| a573d076e4 | |||
| 625cb03284 | |||
| 2f8d60ec47 | |||
| 37e33af342 | |||
| f7e0516254 | |||
| 8e4bdcfb98 | |||
| f3f0ab6e2c | |||
| eafe57e923 | |||
| c76ab138eb | |||
| 5a771732bd | |||
| 9b6647a019 | |||
| 7e40a5a711 | |||
| 27cbd0d931 | |||
| 16c176dc89 | |||
| 12c316cd6b | |||
| b06583133a | |||
| a2e6fc5909 | |||
| 058065ce75 | |||
| 75a2015260 | |||
| 18776aa6b9 | |||
| 4cf48daa75 | |||
| 361aeac0cc | |||
| 2e66d621b5 | |||
| 566a11a585 | |||
| abb9fb3345 | |||
| 05a9652f76 | |||
| ba5df8edca | |||
| 9afee7e8d2 | |||
| c458186f68 | |||
| f9da0a59e4 | |||
| c19af95db0 | |||
| 840459bdb0 | |||
| 798660c007 | |||
| c039977048 | |||
| 7a9737b3d4 | |||
| 0f5d562625 | |||
| 21f9e7f5e5 | |||
| 6ee7b05b27 | |||
| e4c7e9903e | |||
| a96100d875 | |||
| 10c67051f2 | |||
| a3fbd09ef9 | |||
| 51248270e1 | |||
| 8fe431e53e | |||
| 61a7d88490 | |||
| 496765c043 | |||
| a62039882e | |||
| a2a05e40e6 | |||
| 45d08ea992 | |||
| c9c7aa2e90 | |||
| d0037fcf6b | |||
| b25fba6175 | |||
| afcdbf1ba6 | |||
| 8eff75a484 | |||
| e232cabfab | |||
| e5ed388191 | |||
| c0ac3de272 | |||
| abde9a99c3 | |||
| bdc74a03c0 | |||
| 2783461e69 | |||
| 0f9c75dc08 | |||
| cf937c6341 | |||
| 77210ffa56 | |||
| fb5bb1cd83 | |||
| 23c4615f5e | |||
| fa2b68dac6 | |||
| bd86cb22e0 | |||
| ec2635131b | |||
| 6b3cfdfb2b | |||
| bce66e3b42 | |||
| cffa035c1b | |||
| 1097192554 | |||
| 0c10b951a9 | |||
| ab2907cd51 | |||
| ea8d3d4531 | |||
| 256e4a0081 | |||
| e7adfff9bf | |||
| 721c9e2c97 | |||
| 42c7e39c99 | |||
| 96778c69bc | |||
| 4adcc403c2 | |||
| 2cca005056 | |||
| d27109640e | |||
| 931e0d4687 | |||
| 2e3224a138 | |||
| cfa3765d50 | |||
| 1287e8c734 | |||
| 11e884aec5 | |||
| 55a1ba710b | |||
| 0a8b266c71 | |||
| 7a6ac3ea92 | |||
| 394c12f68d | |||
| 1a57ad233d | |||
| c268463413 | |||
| 81fe93127d | |||
| aa5716d3f9 | |||
| f9c6f6856b | |||
| b9cc2606f2 | |||
| 5023313c03 | |||
| 98f9f7d42e | |||
| 3e0fd63682 | |||
| 1f643b5816 | |||
| 14adcb9db8 | |||
| 41a22bd83d | |||
| 648b83d6ea | |||
| 4e97b83312 | |||
| 07cd6cd670 | |||
| 3fae38a2f8 | |||
| 23054138c2 | |||
| 63f755554b | |||
| 2ac463f003 | |||
| 77227c2ff5 | |||
| 2afccd7fbd | |||
| 991181104b | |||
| 70aff9fbb2 | |||
| 2370884722 | |||
| c529b1b73a | |||
| acc29fbceb | |||
| 7cc5177078 | |||
| fc93ea7aa3 | |||
| 4c22982732 | |||
| fb935541c9 | |||
| 47023b2e6c | |||
| f4a390201c | |||
| d358ebd7e6 | |||
| 9711dd1381 | |||
| 4c328d83ba | |||
| 9911b132d2 | |||
| 534e5978d8 | |||
| c08bf1204f | |||
| 94d68c1f22 | |||
| 0ca379ed03 | |||
| 0ed2d8b127 | |||
| 3bee571e1f | |||
| 0b78544796 | |||
| 361f71deed | |||
| 61f39ae0a0 | |||
| 082324d7b9 | |||
| 5e99289d7a | |||
| e14a4e79ae | |||
| 39c85cafa2 | |||
| fa6be4ec58 | |||
| 25b8461bfb | |||
| ac43dd0777 | |||
| 963559676e | |||
| 20ce8c4c51 | |||
| 098c09835b | |||
| 4aa9d34b3d | |||
| 38d2a0ddb9 | |||
| 735bb147e2 | |||
| 7a511308ef | |||
| bc401fa392 | |||
| 96fbafe359 | |||
| e82b0ea4cd | |||
| 2160484b62 | |||
| f0ab58dfbb | |||
| c23b5825bb | |||
| f1872f495a | |||
| 9ed36445b9 | |||
| 5043c10d70 | |||
| e748d2f2af | |||
| ecde06e3a3 | |||
| 3505c1d790 | |||
| 150a72f75e | |||
| f96579824b | |||
| 2aa3cabd85 | |||
| 06d26df046 | |||
| 6e49b1cad7 | |||
| d928f425ec | |||
| ed3a9aed12 | |||
| aaccaa19bf | |||
| 35857d3103 | |||
| d47b0eeee7 | |||
| 287beaff35 | |||
| 8e9d1c7ebf | |||
| 53380632a1 | |||
| 984a95b8c7 | |||
| 72118fcc6a | |||
| 1b06f809de | |||
| 19fe508fb2 | |||
| aaaff9b66c | |||
| c660b43105 | |||
| 92b24fd02d | |||
| 886d0de040 | |||
| 16d797cb01 | |||
| bbf9678756 | |||
| d60c619c44 | |||
| e7abc05931 | |||
| 12dd912ce9 | |||
| 64a63b3879 | |||
| 93caf5b311 | |||
| aab2fa1af9 | |||
| 4cf176de0b | |||
| 735cfcd290 | |||
| 4aa4317c28 | |||
| d0ef6d2a9b | |||
| 434c84043d | |||
| 747116aeb0 | |||
| a182dc78f4 | |||
| 1a316c8a18 | |||
| 46e7fa52b3 | |||
| 52ea3748b4 | |||
| 0a2678973b | |||
| 04129c5bd5 | |||
| 6f363dcae3 | |||
| 8c4bd76280 | |||
| 92f385e7b5 | |||
| ac4e259e29 | |||
| 076b20a9a5 | |||
| 0b0230adce | |||
| e51915a529 | |||
| 187a475b84 | |||
| 39c0a619eb | |||
| 29f7eaad78 | |||
| 8f086a6957 | |||
| 8f512001b6 | |||
| 1d25522a3b | |||
| fdb538538a | |||
| 2feb1bf847 | |||
| 74bbb1167f | |||
| 515163864f | |||
| 1cdb975c91 | |||
| cd42d26eb3 | |||
| 8bc96652cd | |||
| 1631a2bac1 | |||
| 501635ca26 | |||
| edcd335b90 | |||
| 0cb9908f27 | |||
| 61858f5899 | |||
| c5911679d1 | |||
| 99d6a077fe | |||
| 8b680254ee | |||
| b873651da7 | |||
| b185d9e701 | |||
| b635622cac | |||
| b31d8b1ad0 | |||
| 2153cb7e0a | |||
| 15033eab28 | |||
| 8b4c530062 | |||
| 9ff9587b7b | |||
| d8acbda548 | |||
| 7e4a65114a | |||
| d9a2d29d00 | |||
| 27931249ce | |||
| 52318d0e0e | |||
| 8d673789be | |||
| 646c4c7458 | |||
| 2cc22d118d | |||
| 1182f41f99 | |||
| 098d1d2b5e | |||
| 31c85f0ec5 | |||
| 091d1f8c75 | |||
| 6c50e6ef34 | |||
| 67f48aca96 | |||
| fc64e787a3 | |||
| d13bed9a0a | |||
| 904c48b11a | |||
| 2ab5eb7213 | |||
| 5ce541e9ef | |||
| 0cf9c22033 | |||
| 38e06f13d6 | |||
| ccc94f6832 | |||
| 589820639c | |||
| 68b9260c9b | |||
| 49b2447113 | |||
| 89c50bbd82 | |||
| 2b3f3e11d3 | |||
| 4100cfec86 | |||
| cad3a50e4e | |||
| 4d9ee55468 | |||
| b72f009d87 | |||
| 2181e0fc27 | |||
| cd74cdfdaf | |||
| 49ab935ae9 | |||
| 6879c9d8df | |||
| 939bf4bb5d | |||
| 7861dfd667 | |||
| c5fc28de7d | |||
| 535d290293 | |||
| a0dd975686 | |||
| f48531efaf | |||
| c6a4116082 | |||
| aecd6b85e6 | |||
| 55439ef293 | |||
| d4cf103676 | |||
| 489fb087a4 | |||
| ff904ae174 | |||
| d8db5ec7b6 | |||
| 5d8b78cb88 | |||
| 9736402dfd | |||
| 0600054ad4 | |||
| b782fca75b | |||
| 0230b88078 | |||
| 55c9fb7c5c | |||
| 8201a9ce6e | |||
| 561a94cc50 | |||
| 0636887931 | |||
| 0c1b39d881 | |||
| 67ffae7e32 | |||
| 488a38a96d | |||
| 77e5854a16 | |||
| 2a42dab108 | |||
| 092d103d24 | |||
| 12b7df550f | |||
| 006bd2fe17 | |||
| d252768ac5 | |||
| dd7c2c0574 | |||
| c91898a888 | |||
| afa8eb2d6f | |||
| 1481015dc4 | |||
| 8cdedd4cd2 | |||
| 985e4eed60 | |||
| 9d0583e0d2 | |||
| 9aed26a234 | |||
| 3323d5c76c | |||
| 4b9afd787c | |||
| cedf01d094 | |||
| 4a71603a77 | |||
| aadc8477b9 | |||
| 9bf111bd3d | |||
| 8060da2132 | |||
| b495a302b0 | |||
| 9453b2387b | |||
| a4de59c8ee | |||
| fab40080e4 | |||
| fb30bda7d7 | |||
| 65206fe33e | |||
| 2f094134a3 | |||
| 69e1f42aed | |||
| c35c58b023 | |||
| 4b57aec1c6 | |||
| 2038bd0c15 | |||
| 19b24fcce2 | |||
| ed3354b433 | |||
| 963eeee361 | |||
| c3a316664a | |||
| 3d16880d95 | |||
| be6f355665 | |||
| 5dba08fb3b | |||
| f17077c05c | |||
| 8aa36072fc | |||
| 44ea82f845 | |||
| 0de7df9eab | |||
| 60e509b1e0 | |||
| 551c379f1b | |||
| c39a360372 | |||
| 683ee75703 | |||
| f6d1724835 | |||
| a99da47b0d | |||
| 0f217c715e | |||
| c4033c215e | |||
| e914d551e7 | |||
| c6e4b8ed5c | |||
| ab398f3704 | |||
| 699aec331d | |||
| baea6a1da8 | |||
| d2375a79f2 | |||
| ba48093666 | |||
| d4b87f1672 | |||
| e4006eb583 | |||
| b934e4b564 | |||
| 28c97a9467 | |||
| 28fca190ee | |||
| 78116e0ea2 | |||
| 5a50afa1fd | |||
| cf77a0e2b4 | |||
| e2593a6883 | |||
| 00a44d1ddb | |||
| d8445fd9df | |||
| 304db907f5 | |||
| b09cdc0f25 | |||
| bd81c6f5b4 | |||
| 4051dd9522 | |||
| 360cb9eb9a | |||
| 241a939c29 | |||
| 2f9c5d2d0b | |||
| 99c812b02d | |||
| d82c2ce50f | |||
| 6c12156b1a | |||
| eec3b3009f | |||
| 5ac7fe453f | |||
| 4654b41c3e | |||
| b09ea17f0e | |||
| 99ebfc337e | |||
| e5f9458905 | |||
| f9c083073e | |||
| ec0a9a5f8a | |||
| 47b924990f | |||
| 215bebb01a | |||
| 9fffa19c51 | |||
| b54f3d4ee9 | |||
| bcdcad5847 | |||
| 737b8e42e4 | |||
| c61e7c05da | |||
| a919828003 | |||
| 0bd33882b6 | |||
| e0e55a649c | |||
| f32d71eca0 | |||
| 74338733ba | |||
| 5fb98609cd | |||
| 19633ece80 | |||
| fb04103352 | |||
| 9abf43b0d2 | |||
| 7f97274ecc | |||
| b2edab193f | |||
| 184563bbe1 | |||
| 73f25ed182 | |||
| 533f6a552c | |||
| 32ac319525 | |||
| 569397bd7e | |||
| 3535d16c3a | |||
| 7f4efa90c8 | |||
| bab3cd988e | |||
| feda213c0c | |||
| c6593e8cde | |||
| 4d8d3919c0 | |||
| 20dc8b222d | |||
| 55733171c1 | |||
| 988926b59d | |||
| d72f8da6d7 | |||
| 0b697b24bd | |||
| b2c75dc3a2 | |||
| b5b3f1fb42 | |||
| bd73834e19 | |||
| 7f43c24297 | |||
| 1b3657122c | |||
| 0f28857c59 | |||
| 88485d5467 | |||
| 921530dd01 | |||
| dcf3023d93 | |||
| 6ac2c5c6dc | |||
| 45b3ae31af | |||
| b12c46b28a | |||
| 66a20264ab | |||
| d2d243cca8 | |||
| d4194962b0 | |||
| 635d671ee7 | |||
| ee8372145d | |||
| ccb736411b | |||
| e2e5641a45 | |||
| 7ca0b256eb | |||
| ca442defbb | |||
| b17ebeb6f6 | |||
| a8afcf1ca9 | |||
| 6545cc2d48 | |||
| 2a10c8fe5c | |||
| 7cd2d14b64 | |||
| fc5abfd68b | |||
| cb5c821989 | |||
| ab7652010b | |||
| 7990566f6b | |||
| b6baee5f77 | |||
| 24c3ec235a | |||
| 204c0fa4d8 | |||
| 3a0b66d5df | |||
| 07d3122c14 | |||
| c6957e4e31 | |||
| 8068a3899d | |||
| 4c0e9f1f89 | |||
| 3cce972125 | |||
| 52700d6a84 | |||
| 0c80a4b836 | |||
| 46f408cc9f | |||
| 5c068a9062 | |||
| e1fae5b902 | |||
| 20e5e95ff8 | |||
| a238f78855 | |||
| 5b96712ed0 | |||
| f141078073 | |||
| d47fed16a9 | |||
| bc43a8d38d | |||
| ccd5685cee | |||
| f0f8177a19 | |||
| 363b701925 | |||
| 0a897e2fae | |||
| 5f53d815d1 | |||
| 7b89f25818 | |||
| 8ebb84ad1e | |||
| f0e77a309d | |||
| 7ab531bd21 | |||
| d7af6de9b9 | |||
| 3072479c3c | |||
| 62031c24a2 | |||
| aa38889704 | |||
| 17562e476f | |||
| 6495f2cf98 | |||
| ea20b644cc | |||
| bf848637aa | |||
| 759f846b2b | |||
| 3758be55f5 | |||
| 8f4c59b080 | |||
| 1ff6212ffa | |||
| b60d29ae9a | |||
| 38d71e668d | |||
| 7cdf37eaf6 | |||
| 8d9adfd548 | |||
| a3e2d90f4c | |||
| fc81008ab5 | |||
| a1eae6304f | |||
| 49058620f0 | |||
| f68a3639b4 | |||
| f4e87c9720 | |||
| 23bf7973fa | |||
| 67e0751124 | |||
| f76559daf6 | |||
| 5e99ff6769 | |||
| 1ecb4aa9aa | |||
| a2b3c72647 | |||
| 0180a4fcd4 | |||
| abca3ceac8 | |||
| 866a9fdf19 | |||
| 20e954a864 | |||
| 03e40b333a | |||
| ebed66d4ce | |||
| 9e9f3c485b | |||
| d50a844720 | |||
| 89e559296e | |||
| d352e2fa31 | |||
| 71bc452764 | |||
| f048ad13b5 | |||
| d03d5d8f03 | |||
| 6ff0ce15e7 | |||
| 330b393e16 | |||
| a820246f64 | |||
| 1bf4c8c9ba | |||
| ca1d437435 | |||
| 8b8310711e | |||
| cdcb64b0d0 | |||
| 3c0f1caa41 | |||
| 8182ba4ee0 | |||
| 3d9328fd79 | |||
| 6c6f9f7d25 | |||
| c8f475174e | |||
| 3dec55f009 | |||
| 00d60e28c2 | |||
| ea00619c3b | |||
| bbe50bdaf1 | |||
| 6b59aee336 | |||
| 26a5614572 | |||
| 19ea090633 | |||
| 9841b11a54 | |||
| 5a6d5374d7 | |||
| 9099bc0b6e | |||
| e3b43b6e1c | |||
| b0d801f629 | |||
| c48057081e | |||
| ea76e09ea7 | |||
| c9fb078c0f | |||
| 1800030356 | |||
| 43ba2c6226 | |||
| 735181dc0e | |||
| 8a890fd3d3 | |||
| 15e31e47fa | |||
| 9b54b99bf6 | |||
| 67ca9166d3 | |||
| b2ced834ba | |||
| 18746c1444 | |||
| 09f366bec7 | |||
| 3998d0c81e | |||
| 2a002c3882 | |||
| fb756e3463 | |||
| 3c5661b51b | |||
| 26e06ba6a6 | |||
| 7c57dde255 | |||
| 9ec927b9e9 | |||
| 15a0d9f900 | |||
| f26e3c6509 | |||
| 6568625dea | |||
| 427f212170 | |||
| c1fb8eaf1a | |||
| 37469dc9c2 | |||
| dce57627c9 | |||
| 2992ca5df1 | |||
| a5ed5883c7 | |||
| 0036509f74 | |||
| 003c470a4d | |||
| d6540d9077 | |||
| 091c515fea | |||
| 4f2b9835f5 | |||
| 242d3b3c4d | |||
| c66ac9725e | |||
| feacc5cd11 | |||
| 3a761395be | |||
| a78d6fe0b3 | |||
| 08e466938f | |||
| e036155bdb | |||
| 2149afabe1 | |||
| ec32967daa | |||
| fc4a5e61c2 | |||
| e9608c9d05 | |||
| 581eebb197 | |||
| 10fa67fdaa | |||
| 10f2136675 | |||
| d97dd99d91 | |||
| 296674e18b | |||
| 52a926dd90 | |||
| d38ea63c78 | |||
| 2022a7615a | |||
| dca0fae781 | |||
| e16c6c1b6b | |||
| ede9881458 | |||
| a7f8c78358 | |||
| 3a90b40425 | |||
| 454709559b | |||
| c3933cead4 | |||
| 420f93ce78 | |||
| 2a212a7556 | |||
| 145a7a24e8 | |||
| 6c040497ef | |||
| 9ee4b76cd9 | |||
| 3f6775e29b | |||
| 4c17e2e97e | |||
| eac53fed59 | |||
| fed0c2ea26 | |||
| 21c1618d94 | |||
| d37699f51a | |||
| d82bfa98a7 | |||
| 9b15bda055 | |||
| 635842b322 | |||
| 3b8515beb0 | |||
| 7b62b81ebd | |||
| dcf4e51787 | |||
| 7dc09ed450 | |||
| 349641e95f | |||
| 9941ec85d8 | |||
| ef944b903b | |||
| 0c477f2c6b | |||
| 151396507e | |||
| 8441c0c51e | |||
| ae7bf468d1 | |||
| 907ef82d4b | |||
| 7a1ab62987 | |||
| 295cfc905c | |||
| 204924927a | |||
| f622a8393c | |||
| d75df7fd8a | |||
| 2bc5e0ebd7 | |||
| ca6cef9a7d | |||
| 1c2a30d7e9 | |||
| 4a75a1e839 | |||
| 6a2ff3a371 | |||
| 7ce1386d1a | |||
| d6f45e4d76 | |||
| 356f66784f | |||
| 166ab7b600 | |||
| 1cdb0abf80 | |||
| 0defd1d141 | |||
| 24ed07b6d5 | |||
| ecad730945 | |||
| efb7fd919b | |||
| 5d6b923244 | |||
| d8752da7d5 | |||
| 6952124988 | |||
| a6c93e2c41 | |||
| 788f3c22bf | |||
| c194dfbdf7 | |||
| 5e996a1c02 | |||
| b52bf11ea5 | |||
| 7915dde43c | |||
| 7675b9c28f | |||
| ebe5636307 | |||
| 6fe2df1d7d | |||
| 5376d32772 | |||
| 2924e478ee | |||
| 297700ad11 | |||
| 9d29914304 | |||
| b223bc0302 | |||
| 3562a38f8c | |||
| 201544ef8b | |||
| 837ba6c33b | |||
| 3ab01dbc00 | |||
| c241edaa30 | |||
| e0530df98a | |||
| 6cbce9fdff | |||
| c1eb536726 | |||
| b848ae7abb | |||
| f07453d0ae | |||
| 052051244f | |||
| 97490c6445 | |||
| 1247d36a12 | |||
| f3a463000d | |||
| c38842ecb2 | |||
| 8b825b23b1 | |||
| d2f62730bc | |||
| d167d18bb3 | |||
| 508d7c3336 | |||
| 2b31d85cd4 | |||
| e350c37e6f | |||
| 319a465429 | |||
| 9371325246 | |||
| 2fda3cf988 | |||
| 03b7194c97 | |||
| 39bff40a75 | |||
| 3dc6edfd2d | |||
| 762747273e | |||
| 0f392a95ae | |||
| 29786b0024 | |||
| 32ca50a097 | |||
| 8012e6fa43 | |||
| 54b7cefb09 | |||
| 3a61350f4b | |||
| bdbbaf6c88 | |||
| 24a1a8a626 | |||
| 38b64dc5df | |||
| e3360a0e5d | |||
| 4181444734 | |||
| 7958708641 | |||
| 40a8ed535a | |||
| c7d571f0b5 | |||
| 5d54b710e7 | |||
| 248f14a1ef | |||
| b76fc58543 | |||
| 9fc9981a9e | |||
| 8f563df7c5 | |||
| 730192adc4 | |||
| 8bf32ac697 | |||
| 540f724b1f | |||
| d5a8f2298e | |||
| 18c5a53685 | |||
| a1172d31f4 | |||
| 396debb9cb | |||
| c4cb2f2378 | |||
| 74ce99e0d7 | |||
| 89a233ccd2 | |||
| 2df6cabee0 | |||
| 82023cd629 | |||
| 1e17f44991 | |||
| 600c97cc0f | |||
| 7298054974 | |||
| 4d5a442d1f | |||
| 249f42f054 | |||
| 87788142bf | |||
| f0b08a6c67 | |||
| a144a49a9a | |||
| 2167f1b567 | |||
| c5c723b80c | |||
| 66461c9dbc | |||
| d77103e53e | |||
| 963908e508 | |||
| 9e5677ab02 | |||
| 46bb9bc5c7 | |||
| 118ab60588 | |||
| 223ae61c89 | |||
| 1f4baba06e | |||
| fa1ce7d5d1 | |||
| 775a488a36 | |||
| 018904f0ec | |||
| b358641e7d | |||
| ff745e0ad8 | |||
| 4201834b18 | |||
| 2631e07bea | |||
| 76a1851cb8 | |||
| 87a1792677 | |||
| 413077a5d9 | |||
| d56fdd2937 | |||
| 6639b7d017 | |||
| 7702a488e5 | |||
| 3108752a0c | |||
| 56c0d32ea0 | |||
| c0e84b0592 | |||
| f2e590be7a | |||
| 60ec3594ab | |||
| 49d1f6aca0 | |||
| 49cd9648b0 | |||
| 1692dcf8d5 | |||
| 5ec4719124 | |||
| 911c98e235 | |||
| 535c64c318 | |||
| 171f38b9b5 | |||
| b2645b3201 | |||
| a9936d1570 | |||
| 3032a4274d | |||
| 31c21a054b | |||
| def4fdc3f3 | |||
| 3fed1af7df | |||
| adb4692ce8 | |||
| bb4ff84a4a | |||
| 5d2c1b175e | |||
| 2ab6de8ee4 | |||
| 1896ae5d15 | |||
| 6e4fab19a2 | |||
| 103dcfe897 | |||
| 8caadbacf7 | |||
| 870d776875 | |||
| 59e66ffe49 | |||
| 418a0132d0 | |||
| a381846034 | |||
| 1c5ce75d9f | |||
| 8693a045bb | |||
| b567679eb6 | |||
| e6c8d3d1db | |||
| 12c4afd824 | |||
| 968a07ed7a | |||
| f9c600a760 | |||
| 82561cfbac | |||
| 277ae4e2b0 | |||
| 0f9e747583 | |||
| 4e146a75b6 | |||
| 33d0e2037b | |||
| 7a04b7262e | |||
| f2d5e4b995 | |||
| ada42aa184 | |||
| ed580b3060 | |||
| 29e4762011 | |||
| eff4833840 | |||
| 9867037aa2 | |||
| 57c14f6a9b | |||
| 1ed105205c | |||
| 8233f49beb | |||
| 2c01a4613c | |||
| b0eda47b26 | |||
| 291111e626 | |||
| 47693da4aa | |||
| 9f39209712 | |||
| c47dcbbe2f | |||
| f313538ea5 | |||
| 956ffdf654 | |||
| ef4a527c36 | |||
| 3fe0680ad5 | |||
| 182b269e46 | |||
| 05856ac93e | |||
| 60c29e195a | |||
| 6b23662ce6 | |||
| 77d6364405 | |||
| 077a611a5e | |||
| e82146bf17 | |||
| 0c3522133d | |||
| 1223e8cf7f | |||
| bcb01bdc52 | |||
| dfb5f8ea2c | |||
| 02eab95dd1 | |||
| 67a1e6e46a | |||
| fda1e4409c | |||
| 703c1b0fcf | |||
| e1654e9dd3 | |||
| f8bdd42027 | |||
| f5dcbf517b | |||
| 075193af1d | |||
| 808e7ed4ae | |||
| f0ba5d3821 | |||
| 88f6b5f16b | |||
| 68e6e1b779 | |||
| 9528325777 | |||
| b3aa6afba9 | |||
| 716fe2f427 | |||
| 7df1cc075c | |||
| b0f0a02d3c | |||
| 7cda64e52d | |||
| d6d34bd62f | |||
| 68dde07d5d | |||
| fad4ae8eb2 | |||
| acd8a4bc95 | |||
| 6714e05183 | |||
| f9b5f2b7b1 | |||
| 67fa5df89c | |||
| 023cc9ca54 | |||
| b7924de5c6 | |||
| 4b4481ea27 | |||
| 47be46ae60 | |||
| e84802468b | |||
| 623d789529 | |||
| 827f36e2c0 | |||
| 1a5ed4eb7f | |||
| 5151403aaa | |||
| d5772c939a | |||
| 19097bc5bc | |||
| dbebe9e92c | |||
| be0a543077 | |||
| 67b6a8ee89 | |||
| 780375d865 | |||
| cbcf94669e | |||
| 46da53ba15 | |||
| 06e8d03fba | |||
| 65bf7f6653 | |||
| a6b9341593 | |||
| 47610725ea | |||
| 341ba34773 | |||
| 3b2864d8a6 | |||
| c7d4af5c79 | |||
| f2ec438166 | |||
| a95b064d6d | |||
| c503a75873 | |||
| 9a982cc5b5 | |||
| 685f7d0fea | |||
| f5d9ca64f9 | |||
| cde442fa2c | |||
| 84f966cb8f | |||
| b2b88f1d99 | |||
| 9d23a392a6 | |||
| 57214c63cb | |||
| 6726df4d58 | |||
| 02a58c1247 | |||
| 72a7b35513 | |||
| 2d699fd13b | |||
| 13c321b8fb | |||
| fa42a788c8 | |||
| 843eaf8893 | |||
| 30fa8f8ac2 | |||
| 0ec4e8d5d4 | |||
| af63eff8d7 | |||
| b5d2dd617d | |||
| 8d951ab7f1 | |||
| e24315eed8 | |||
| dc55e88588 | |||
| 7abaf77292 | |||
| e79883e4fd | |||
| 5da76ae34b | |||
| a6d5f9877f | |||
| 994825671d | |||
| b7b5043aea | |||
| 1bf4a6f711 | |||
| 073f51e284 | |||
| b5784bc2ef | |||
| b42bb5be26 | |||
| b6f356c211 | |||
| b052da1065 | |||
| 586e85281e | |||
| ec3ea3752f | |||
| 8294480cb4 | |||
| 6fe8692b98 | |||
| d8e0a86600 | |||
| 8b29b07f5a | |||
| 1d6936fafc | |||
| b22d71a74e | |||
| 7fc2081543 | |||
| b8c2b0105b | |||
| d72db2698b | |||
| e0d9092df8 | |||
| f863264af6 | |||
| 14736c2a8b | |||
| 0af1b75a02 | |||
| 7a8aa03e54 | |||
| 846c0f7cfc | |||
| 1886193c6c | |||
| 100e907890 | |||
| 383c222553 | |||
| ae6e76bbb3 | |||
| ed7284add2 | |||
| 9ecbd70daa | |||
| b8989d9bf9 | |||
| 0f1c5b3891 | |||
| 41ff7a6010 | |||
| 0234f50da1 | |||
| d7cc166eab | |||
| eef44425c3 | |||
| 167b320cdd | |||
| dcf53236ff | |||
| 5b1a531755 | |||
| 97b2d1fe5c | |||
| c5af69ffa6 | |||
| 12d56103d9 | |||
| 8ff713f3bb | |||
| 03972d565e | |||
| 4dcf253330 | |||
| 012f386057 | |||
| 3fa684d6ba | |||
| 8c327567c0 | |||
| 31bc982a53 | |||
| cbd2d89637 | |||
| 67151d39e1 | |||
| d715158fe3 | |||
| 75c0eef6ac | |||
| 4030c5a689 | |||
| 119cafd963 | |||
| 5fc54ec7e5 | |||
| fb0b9de7a9 | |||
| 2c9156e2c1 | |||
| 236347b5bc | |||
| c5d2b01923 | |||
| bf75fd9d34 | |||
| 9a8c69d1c0 | |||
| 6c943722f3 | |||
| 219343f3c0 | |||
| 36b2f13ee0 | |||
| 70ce878dfb | |||
| 9c1612f122 | |||
| 6cba4d3483 | |||
| 738cf837de | |||
| 2550918f27 | |||
| aa5a222c6d | |||
| 2795f09fa8 | |||
| adcaace03c | |||
| f205df1996 | |||
| c59ad24856 | |||
| 2b9b0ac62e | |||
| 08bc6a1698 | |||
| 67e6f57192 | |||
| 24ddb8506f | |||
| 6ff0cc0b40 | |||
| 7620fe1ac6 | |||
| 22e0f5ecd0 | |||
| fce2042375 | |||
| 57594153a1 | |||
| ff93ea5bf1 | |||
| 4a54676f31 | |||
| 0d900521bc | |||
| bd7ffcc048 | |||
| 2f771bee7b | |||
| ae5214c1f2 | |||
| 24493e89ad | |||
| 84d8798ad3 | |||
| 0570c84a83 | |||
| a3860e23c6 | |||
| ab7e1e01de | |||
| bbafc3fbd6 | |||
| 194fa7cd98 | |||
| 4c12addcaf | |||
| 0bd27381c3 | |||
| 6dce07790a | |||
| 203ae32b79 | |||
| 3c493194c9 | |||
| 692764aad3 | |||
| 937e5de1d8 | |||
| 7de67f8c1b | |||
| f5d66bcb6f | |||
| bf82c40964 | |||
| aa6299f114 | |||
| 7ffca8ed58 | |||
| 030405dbb6 | |||
| 8862f9118b | |||
| e2e98672bd | |||
| 51f295cacc | |||
| 0c50ac3396 | |||
| 2da81a4a26 | |||
| b6d4853a33 | |||
| 020b147222 | |||
| 34b037f19b | |||
| 88ee5d1a6d | |||
| 0892d84c17 | |||
| 2501d50f9c | |||
| 1e4a4181e2 | |||
| 3e1daa002c | |||
| 4c13dee18f | |||
| 95497626e3 | |||
| 9ada48054f | |||
| 99d6c58971 | |||
| b974b3ccfd | |||
| 75cf45f0be | |||
| d337a11e83 | |||
| a86386d882 | |||
| bbf40bf318 | |||
| b054585066 | |||
| 90c44c34a9 | |||
| e449cc9e2d | |||
| 909ed93cd3 | |||
| 9c97b11ab9 | |||
| 5ae44b25da | |||
| b2ecb37b35 | |||
| 144d034475 | |||
| 50d8dc91cf | |||
| e58915e12f | |||
| 7f8c2a44a4 | |||
| d986eee36b | |||
| b3e712e0b8 | |||
| 05434daa69 | |||
| 2c4a478987 | |||
| a80ca23937 | |||
| ba02ef8f25 | |||
| ef3d8bdc42 | |||
| 951511704d | |||
| 23aae6ab0f | |||
| 3748e117a9 | |||
| 33798b8b80 | |||
| 2e85083d0a | |||
| 23b8a9033a | |||
| 313b6874b1 | |||
| 6004412365 | |||
| adac039a2b | |||
| adcc865c70 | |||
| fe533fb809 | |||
| fa62963da7 | |||
| 1f5bb99548 | |||
| f1cd56c28a | |||
| 852c8b533c | |||
| 582a72574e | |||
| b249ddde48 | |||
| b020ba2b5f | |||
| 03c6862d51 | |||
| b7f953b2ee | |||
| 0b064765c9 | |||
| eb3ddce706 | |||
| 5fdc9fa3b6 | |||
| bfb231fb8a | |||
| 74fb74d9cb | |||
| 97d7e295dd | |||
| 0727e91aeb | |||
| 8dc70f797c | |||
| 2cf8a9da6f | |||
| c1c7128634 | |||
| 0e9ef50e63 | |||
| e05944601a | |||
| 49cf0125a9 | |||
| 0602a16ad6 | |||
| 09a0dad115 | |||
| 243a3f5006 | |||
| 33ca85bd4e | |||
| ca15eb26f0 | |||
| 28eebc14d0 | |||
| 4210aa9ab9 | |||
| 5bbdbadc25 | |||
| 00f24a3249 | |||
| d8a798372b | |||
| 8d5c865814 | |||
| 5134d6bc63 | |||
| ede57720fd | |||
| 830d2007a6 | |||
| 5f3b6c9722 | |||
| 93f7d3bfb9 | |||
| f0ef10aa57 | |||
| bf91fcc6f7 | |||
| 2d894a0164 | |||
| 731b9c902f | |||
| ac0f3c8433 | |||
| 56bfbbf501 | |||
| 63b5d472fa | |||
| 233e3c76fd | |||
| 2334dadb6a | |||
| 6f4f2754d6 | |||
| 30ced04137 | |||
| c39bd7e089 | |||
| 3470d986f0 | |||
| 7c0257fcda | |||
| 9af6d6c9c6 | |||
| 1ecab2fcbc | |||
| a262c0bbf3 | |||
| 7f3f164736 | |||
| 085db569f1 | |||
| 133af6f826 | |||
| 1c2301e2f1 | |||
| ef999f660b | |||
| fad330acd1 | |||
| 8f1af2630d | |||
| eea92a3371 | |||
| ff275df5ea | |||
| 6e56e5457d | |||
| afaa5f2deb | |||
| 0674b1b6ee | |||
| 1ef8602f19 | |||
| ee597fc9b8 | |||
| e254581a1b | |||
| 38ea140b3f | |||
| d939d6079a | |||
| 6e9475d61d | |||
| f6134422e6 | |||
| 5c05038af0 | |||
| 5da5ebff13 | |||
| 798932523e | |||
| 5267a864db | |||
| f02334237a | |||
| d5ea492ef5 | |||
| 96ac405952 | |||
| 38d58e818c | |||
| 2d71ab6f29 | |||
| 090723179b | |||
| 5b55fbff23 | |||
| 64f200dc74 | |||
| 99e2f0c91e | |||
| c02ff3af27 | |||
| 553f338f6f | |||
| bb72c804fb | |||
| 13c6352b8e | |||
| 707c2b3d7a | |||
| 14eed79a21 | |||
| 2ca30e3acd | |||
| caf9716bf1 | |||
| d569daae33 | |||
| 28f7f57247 | |||
| ffc592c7cf | |||
| 3567c006e6 | |||
| b9db450a7d | |||
| 0d65c6dcf7 | |||
| dfee7c103e | |||
| 025fc2685d | |||
| 5b5154eda0 | |||
| ecf65303cd | |||
| 8ea6972496 | |||
| 9afd9f9bea | |||
| c8d3a9121b | |||
| f0950e2286 | |||
| edd78ae129 | |||
| 8738695bd8 | |||
| 76cb3b7874 | |||
| 02a098eb48 | |||
| 1f17a391c6 | |||
| a8fb346fd7 | |||
| 96fb5eb0ba | |||
| 9c7656d59a | |||
| a53bff5645 | |||
| a9182cfd8c | |||
| de6c0f682f | |||
| 9cfcb43725 | |||
| d9b590c76e | |||
| 450c535e9a | |||
| 0dc166e594 | |||
| 8ba080a66d | |||
| 7801582819 | |||
| bc882e678d | |||
| 58e173f279 | |||
| b7d7b9d6b3 | |||
| cf091a48b4 | |||
| d9bfe9e5d4 | |||
| 245a6697ef | |||
| 6226c2978d | |||
| 3d325e52c6 | |||
| 6a6d7701f9 | |||
| 50c688f0f7 | |||
| ef99d03f21 | |||
| af265250c2 | |||
| c6f463b8c9 | |||
| b7d75e2f1d | |||
| 6aa54cbe9a | |||
| 090e30f07b | |||
| f5d507a9b9 | |||
| 8e5e43f335 | |||
| b9f7b2fdfa | |||
| 59a601f2cf | |||
| b6a5c5f5d2 | |||
| a2f02b8b32 | |||
| ee4ed126e1 | |||
| c36dc91849 | |||
| 91dccf8d62 | |||
| 1fc3a25f47 | |||
| 7322b63991 | |||
| f860b09065 | |||
| 45b742be23 | |||
| d325ee4b91 | |||
| 87d6910bb8 | |||
| 9c9300ed58 | |||
| e559cf32fe | |||
| f2202db517 | |||
| fb735883be | |||
| 6a2ef1f4f3 | |||
| 051c9cb564 | |||
| eb60ec3899 | |||
| 233f47cc99 | |||
| c386c72d10 | |||
| 20eacc4a84 | |||
| a28699b42d | |||
| 4d74d5bc99 | |||
| ed371f2b0d | |||
| 66f2881a78 | |||
| 7d4e9497eb | |||
| c08809e29d | |||
| 99460c9e32 | |||
| d86df8321c | |||
| 806f56ca38 | |||
| c40b6c7c2f | |||
| 896b7145b3 | |||
| 8a2a70a3c2 | |||
| 97352538ad | |||
| c6c4ad6188 | |||
| 210f47b8ab | |||
| 94c1331c07 | |||
| d6407e9636 | |||
| df58a00564 | |||
| d546677ae7 | |||
| 04b1023988 | |||
| 9a81071687 | |||
| 48685e8bf1 | |||
| 0f697a0f26 | |||
| 8ddb493b96 | |||
| 039d9938b9 | |||
| f50ea649f6 | |||
| 6e647a88eb | |||
| 986cba584e | |||
| b427a4c8c9 | |||
| 133ee70a5b | |||
| 494612827a | |||
| 1113f23475 | |||
| 8626f58773 | |||
| 7032867421 | |||
| e6239ca3c2 | |||
| 162628000f | |||
| 55b79c078c | |||
| 570b127869 | |||
| 6179d4feb1 | |||
| 2ff5d016d5 | |||
| 854a95327a | |||
| 8a16fd7699 | |||
| 7bbcf22deb | |||
| 0324281634 | |||
| de0a3e0ab9 | |||
| d26110da7f | |||
| 60e73d91f6 | |||
| 5eeb436626 | |||
| 802333e454 | |||
| eb457d688d | |||
| 34cb558279 | |||
| f36e19e86f | |||
| 86fada718e | |||
| 2a94b66f4d | |||
| 4ee413aa32 | |||
| 2d824e4809 | |||
| 9474c99795 | |||
| 84a7f222ff | |||
| d29423c24e | |||
| 02a8bba02e | |||
| 6ea68869c9 |
@@ -0,0 +1,10 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
end_of_line = lf
|
||||
|
||||
[*.y{,a}ml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
tab_width = 2
|
||||
@@ -1 +1,2 @@
|
||||
*.odin linguist-language=Odin
|
||||
* text=auto
|
||||
+20
-18
@@ -58,8 +58,8 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM, botan and setup PATH
|
||||
run: |
|
||||
brew install llvm@11 botan
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
brew install llvm@13 botan
|
||||
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
@@ -87,11 +87,6 @@ jobs:
|
||||
cd tests/core
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Vendor library tests
|
||||
run: |
|
||||
cd tests/vendor
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin internals tests
|
||||
run: |
|
||||
cd tests/internal
|
||||
@@ -104,13 +99,13 @@ jobs:
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||
timeout-minutes: 10
|
||||
build_windows:
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
./build.bat 1
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
@@ -121,58 +116,65 @@ jobs:
|
||||
- name: Odin check
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\core
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Vendor library tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\vendor
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Odin internals tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\internal
|
||||
call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: Odin documentation tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\documentation
|
||||
rem call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: core:math/big tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\core\math\big
|
||||
call build.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
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style -target:windows_i386
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -7,26 +7,29 @@ on:
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-2019
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
./build.bat 1 1
|
||||
- name: Odin run
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
run: |
|
||||
rm bin/llvm/windows/LLVM-C.lib
|
||||
mkdir dist
|
||||
cp odin.exe dist
|
||||
cp LICENSE dist
|
||||
cp LLVM-C.dll dist
|
||||
cp -r shared dist
|
||||
cp -r base dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
cp -r bin dist
|
||||
@@ -37,6 +40,7 @@ jobs:
|
||||
name: windows_artifacts
|
||||
path: dist
|
||||
build_ubuntu:
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -50,8 +54,10 @@ jobs:
|
||||
run: |
|
||||
mkdir dist
|
||||
cp odin dist
|
||||
cp LICENSE dist
|
||||
cp libLLVM* dist
|
||||
cp -r shared dist
|
||||
cp -r base dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
cp -r examples dist
|
||||
@@ -61,13 +67,14 @@ jobs:
|
||||
name: ubuntu_artifacts
|
||||
path: dist
|
||||
build_macos:
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM and setup PATH
|
||||
run: |
|
||||
brew install llvm@11
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
brew install llvm@13
|
||||
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
@@ -78,7 +85,9 @@ jobs:
|
||||
run: |
|
||||
mkdir dist
|
||||
cp odin dist
|
||||
cp LICENSE dist
|
||||
cp -r shared dist
|
||||
cp -r base dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
cp -r examples dist
|
||||
|
||||
+33
-1
@@ -22,6 +22,34 @@ bld/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
![Cc]ore/[Ll]og/
|
||||
tests/documentation/verify/
|
||||
tests/documentation/all.odin-doc
|
||||
tests/internal/test_map
|
||||
tests/internal/test_pow
|
||||
tests/internal/test_rtti
|
||||
tests/core/test_core_compress
|
||||
tests/core/test_core_filepath
|
||||
tests/core/test_core_fmt
|
||||
tests/core/test_core_i18n
|
||||
tests/core/test_core_image
|
||||
tests/core/test_core_libc
|
||||
tests/core/test_core_match
|
||||
tests/core/test_core_math
|
||||
tests/core/test_core_net
|
||||
tests/core/test_core_os_exit
|
||||
tests/core/test_core_reflect
|
||||
tests/core/test_core_strings
|
||||
tests/core/test_crypto_hash
|
||||
tests/core/test_hash
|
||||
tests/core/test_hxa
|
||||
tests/core/test_json
|
||||
tests/core/test_linalg_glsl_math
|
||||
tests/core/test_noise
|
||||
tests/core/test_varint
|
||||
tests/core/test_xml
|
||||
tests/core/test_core_slice
|
||||
tests/core/test_core_thread
|
||||
tests/vendor/vendor_botan
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Visual Studio Code options directory
|
||||
@@ -268,6 +296,7 @@ bin/
|
||||
|
||||
# - Linux/MacOS
|
||||
odin
|
||||
!odin/
|
||||
odin.dSYM
|
||||
*.bin
|
||||
demo.bin
|
||||
@@ -284,4 +313,7 @@ shared/
|
||||
*.sublime-workspace
|
||||
examples/bug/
|
||||
build.sh
|
||||
!core/debug/
|
||||
!core/debug/
|
||||
|
||||
# RAD debugger project file
|
||||
*.raddbg
|
||||
BIN
Binary file not shown.
@@ -11,7 +11,7 @@
|
||||
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://discord.gg/odinlang">
|
||||
<a href="https://discord.com/invite/sVBPHEv">
|
||||
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
||||
</a>
|
||||
<a href="https://github.com/odin-lang/odin/actions">
|
||||
|
||||
@@ -94,7 +94,15 @@ cap :: proc(array: Array_Type) -> int ---
|
||||
|
||||
size_of :: proc($T: typeid) -> int ---
|
||||
align_of :: proc($T: typeid) -> int ---
|
||||
offset_of :: proc($T: typeid) -> uintptr ---
|
||||
|
||||
// e.g. offset_of(t.f), where t is an instance of the type T
|
||||
offset_of_selector :: proc(selector: $T) -> uintptr ---
|
||||
// e.g. offset_of(T, f), where T can be the type instead of a variable
|
||||
offset_of_member :: proc($T: typeid, member: $M) -> uintptr ---
|
||||
offset_of :: proc{offset_of_selector, offset_of_member}
|
||||
// e.g. offset_of(T, "f"), where T can be the type instead of a variable
|
||||
offset_of_by_string :: proc($T: typeid, member: string) -> uintptr ---
|
||||
|
||||
type_of :: proc(x: expr) -> type ---
|
||||
type_info_of :: proc($T: typeid) -> ^runtime.Type_Info ---
|
||||
typeid_of :: proc($T: typeid) -> typeid ---
|
||||
@@ -102,14 +110,14 @@ typeid_of :: proc($T: typeid) -> typeid ---
|
||||
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
|
||||
|
||||
complex :: proc(real, imag: Float) -> Complex_Type ---
|
||||
quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type ---
|
||||
quaternion :: proc(imag, jmag, kmag, real: Float) -> Quaternion_Type --- // fields must be named
|
||||
real :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||
jmag :: proc(value: Quaternion) -> Float ---
|
||||
kmag :: proc(value: Quaternion) -> Float ---
|
||||
conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion ---
|
||||
|
||||
expand_to_tuple :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
expand_values :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
|
||||
min :: proc(values: ..T) -> T ---
|
||||
max :: proc(values: ..T) -> T ---
|
||||
@@ -5,6 +5,12 @@ package intrinsics
|
||||
// Package-Related
|
||||
is_package_imported :: proc(package_name: string) -> bool ---
|
||||
|
||||
// Matrix Related Procedures
|
||||
transpose :: proc(m: $T/matrix[$R, $C]$E) -> matrix[C, R]E ---
|
||||
outer_product :: proc(a: $A/[$X]$E, b: $B/[$Y]E) -> matrix[X, Y]E ---
|
||||
hadamard_product :: proc(a, b: $T/matrix[$R, $C]$E) -> T ---
|
||||
matrix_flatten :: proc(m: $T/matrix[$R, $C]$E) -> [R*C]E ---
|
||||
|
||||
// Types
|
||||
soa_struct :: proc($N: int, $T: typeid) -> type/#soa[N]T
|
||||
|
||||
@@ -162,7 +168,14 @@ type_is_matrix :: proc($T: typeid) -> bool ---
|
||||
type_has_nil :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_specialization_of :: proc($T, $S: typeid) -> bool ---
|
||||
|
||||
type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) ---
|
||||
type_union_tag_type :: proc($T: typeid) -> typeid where type_is_union(T) ---
|
||||
type_union_tag_offset :: proc($T: typeid) -> uintptr where type_is_union(T) ---
|
||||
type_union_base_tag_value :: proc($T: typeid) -> int where type_is_union(U) ---
|
||||
type_union_variant_count :: proc($T: typeid) -> int where type_is_union(T) ---
|
||||
type_variant_type_of :: proc($T: typeid, $index: int) -> typeid where type_is_union(T) ---
|
||||
type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) ---
|
||||
|
||||
type_has_field :: proc($T: typeid, $name: string) -> bool ---
|
||||
type_field_type :: proc($T: typeid, $name: string) -> typeid ---
|
||||
@@ -192,6 +205,7 @@ type_map_info :: proc($T: typeid/map[$K]$V) -> ^runtime.Map_Info ---
|
||||
type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info ---
|
||||
|
||||
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
|
||||
type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
|
||||
|
||||
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||
|
||||
@@ -214,10 +228,10 @@ simd_shr_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T
|
||||
simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_neg :: proc(a: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
@@ -283,7 +297,7 @@ wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -
|
||||
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
|
||||
|
||||
// x86 Targets (i386, amd64)
|
||||
x86_cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
|
||||
x86_cpuid :: proc(ax, cx: u32) -> (eax, ebx, ecx, edx: u32) ---
|
||||
x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
||||
|
||||
|
||||
@@ -305,4 +319,4 @@ valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2,
|
||||
|
||||
// Internal compiler use only
|
||||
|
||||
__entry_point :: proc() ---
|
||||
__entry_point :: proc() ---
|
||||
@@ -18,9 +18,10 @@
|
||||
// This could change at a later date if the all these data structures are
|
||||
// implemented within the compiler rather than in this "preload" file
|
||||
//
|
||||
//+no-instrumentation
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
// NOTE(bill): This must match the compiler's
|
||||
Calling_Convention :: enum u8 {
|
||||
@@ -83,8 +84,8 @@ Type_Info_Multi_Pointer :: struct {
|
||||
elem: ^Type_Info,
|
||||
}
|
||||
Type_Info_Procedure :: struct {
|
||||
params: ^Type_Info, // Type_Info_Tuple
|
||||
results: ^Type_Info, // Type_Info_Tuple
|
||||
params: ^Type_Info, // Type_Info_Parameters
|
||||
results: ^Type_Info, // Type_Info_Parameters
|
||||
variadic: bool,
|
||||
convention: Calling_Convention,
|
||||
}
|
||||
@@ -104,10 +105,12 @@ Type_Info_Enumerated_Array :: struct {
|
||||
}
|
||||
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int}
|
||||
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int}
|
||||
Type_Info_Tuple :: struct { // Only used for procedures parameters and results
|
||||
|
||||
Type_Info_Parameters :: struct { // Only used for procedures parameters and results
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
}
|
||||
Type_Info_Tuple :: Type_Info_Parameters // Will be removed eventually
|
||||
|
||||
Type_Info_Struct :: struct {
|
||||
types: []^Type_Info,
|
||||
@@ -117,6 +120,7 @@ Type_Info_Struct :: struct {
|
||||
tags: []string,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
is_no_copy: bool,
|
||||
custom_align: bool,
|
||||
|
||||
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
|
||||
@@ -159,11 +163,11 @@ Type_Info_Simd_Vector :: struct {
|
||||
count: int,
|
||||
}
|
||||
Type_Info_Relative_Pointer :: struct {
|
||||
pointer: ^Type_Info,
|
||||
pointer: ^Type_Info, // ^T
|
||||
base_integer: ^Type_Info,
|
||||
}
|
||||
Type_Info_Relative_Slice :: struct {
|
||||
slice: ^Type_Info,
|
||||
Type_Info_Relative_Multi_Pointer :: struct {
|
||||
pointer: ^Type_Info, // [^]T
|
||||
base_integer: ^Type_Info,
|
||||
}
|
||||
Type_Info_Matrix :: struct {
|
||||
@@ -208,7 +212,7 @@ Type_Info :: struct {
|
||||
Type_Info_Enumerated_Array,
|
||||
Type_Info_Dynamic_Array,
|
||||
Type_Info_Slice,
|
||||
Type_Info_Tuple,
|
||||
Type_Info_Parameters,
|
||||
Type_Info_Struct,
|
||||
Type_Info_Union,
|
||||
Type_Info_Enum,
|
||||
@@ -216,7 +220,7 @@ Type_Info :: struct {
|
||||
Type_Info_Bit_Set,
|
||||
Type_Info_Simd_Vector,
|
||||
Type_Info_Relative_Pointer,
|
||||
Type_Info_Relative_Slice,
|
||||
Type_Info_Relative_Multi_Pointer,
|
||||
Type_Info_Matrix,
|
||||
Type_Info_Soa_Pointer,
|
||||
},
|
||||
@@ -249,12 +253,13 @@ Typeid_Kind :: enum u8 {
|
||||
Bit_Set,
|
||||
Simd_Vector,
|
||||
Relative_Pointer,
|
||||
Relative_Slice,
|
||||
Relative_Multi_Pointer,
|
||||
Matrix,
|
||||
Soa_Pointer,
|
||||
}
|
||||
#assert(len(Typeid_Kind) < 32)
|
||||
|
||||
// Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
||||
// Typeid_Bit_Field :: bit_field #align(align_of(uintptr)) {
|
||||
// index: 8*size_of(uintptr) - 8,
|
||||
// kind: 5, // Typeid_Kind
|
||||
// named: 1,
|
||||
@@ -302,6 +307,7 @@ Allocator_Mode :: enum byte {
|
||||
Query_Features,
|
||||
Query_Info,
|
||||
Alloc_Non_Zeroed,
|
||||
Resize_Non_Zeroed,
|
||||
}
|
||||
|
||||
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
|
||||
@@ -334,6 +340,8 @@ Kilobyte :: 1024 * Byte
|
||||
Megabyte :: 1024 * Kilobyte
|
||||
Gigabyte :: 1024 * Megabyte
|
||||
Terabyte :: 1024 * Gigabyte
|
||||
Petabyte :: 1024 * Terabyte
|
||||
Exabyte :: 1024 * Petabyte
|
||||
|
||||
// Logging stuff
|
||||
|
||||
@@ -422,7 +430,7 @@ Raw_Map :: struct {
|
||||
// Map_Hash directly, though for consistency sake it's written as if it were
|
||||
// an array of Map_Cell(Map_Hash).
|
||||
data: uintptr, // 8-bytes on 64-bits, 4-bytes on 32-bits
|
||||
len: int, // 8-bytes on 64-bits, 4-bytes on 32-bits
|
||||
len: uintptr, // 8-bytes on 64-bits, 4-bytes on 32-bits
|
||||
allocator: Allocator, // 16-bytes on 64-bits, 8-bytes on 32-bits
|
||||
}
|
||||
|
||||
@@ -468,7 +476,7 @@ Odin_OS_Type :: type_of(ODIN_OS)
|
||||
arm32,
|
||||
arm64,
|
||||
wasm32,
|
||||
wasm64,
|
||||
wasm64p32,
|
||||
}
|
||||
*/
|
||||
Odin_Arch_Type :: type_of(ODIN_ARCH)
|
||||
@@ -496,6 +504,29 @@ Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
|
||||
Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
||||
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Platform_Subtarget_Type :: enum int {
|
||||
Default,
|
||||
iOS,
|
||||
}
|
||||
*/
|
||||
Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Sanitizer_Flag :: enum u32 {
|
||||
Address = 0,
|
||||
Memory = 1,
|
||||
Thread = 2,
|
||||
}
|
||||
Odin_Sanitizer_Flags :: distinct bitset[Odin_Sanitizer_Flag; u32]
|
||||
|
||||
ODIN_SANITIZER_FLAGS // is a constant
|
||||
*/
|
||||
Odin_Sanitizer_Flags :: type_of(ODIN_SANITIZER_FLAGS)
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Init Startup Procedures //
|
||||
/////////////////////////////
|
||||
@@ -505,11 +536,8 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
||||
foreign {
|
||||
@(link_name="__$startup_runtime")
|
||||
_startup_runtime :: proc "odin" () ---
|
||||
}
|
||||
|
||||
@(link_name="__$cleanup_runtime")
|
||||
_cleanup_runtime :: proc() {
|
||||
default_temp_allocator_destroy(&global_default_temp_allocator_data)
|
||||
@(link_name="__$cleanup_runtime")
|
||||
_cleanup_runtime :: proc "odin" () ---
|
||||
}
|
||||
|
||||
_cleanup_runtime_contextless :: proc "contextless" () {
|
||||
@@ -566,7 +594,7 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check
|
||||
return &type_table[n]
|
||||
}
|
||||
|
||||
when !ODIN_DISALLOW_RTTI {
|
||||
when !ODIN_NO_RTTI {
|
||||
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_of(id)
|
||||
ti = type_info_base(ti)
|
||||
@@ -622,7 +650,9 @@ __init_context :: proc "contextless" (c: ^Context) {
|
||||
c.allocator.data = nil
|
||||
|
||||
c.temp_allocator.procedure = default_temp_allocator_proc
|
||||
c.temp_allocator.data = &global_default_temp_allocator_data
|
||||
when !NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
c.temp_allocator.data = &global_default_temp_allocator_data
|
||||
}
|
||||
|
||||
when !ODIN_DISABLE_ASSERT {
|
||||
c.assertion_failure_proc = default_assertion_failure_proc
|
||||
@@ -636,8 +666,10 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
|
||||
when ODIN_OS == .Freestanding {
|
||||
// Do nothing
|
||||
} else {
|
||||
print_caller_location(loc)
|
||||
print_string(" ")
|
||||
when !ODIN_DISABLE_ASSERT {
|
||||
print_caller_location(loc)
|
||||
print_string(" ")
|
||||
}
|
||||
print_string(prefix)
|
||||
if len(message) > 0 {
|
||||
print_string(": ")
|
||||
@@ -1,12 +1,12 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
@builtin
|
||||
Maybe :: union($T: typeid) {T}
|
||||
|
||||
|
||||
@builtin
|
||||
@(builtin, require_results)
|
||||
container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: typeid, $field_name: string) -> ^T
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Field_Type {
|
||||
@@ -15,14 +15,23 @@ container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: type
|
||||
}
|
||||
|
||||
|
||||
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
|
||||
when !NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR)
|
||||
init_global_temporary_allocator :: proc(size: int, backup_allocator := context.allocator) {
|
||||
default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
|
||||
when !NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// `copy_slice` is a built-in procedure that copies elements from a source slice `src` to a destination slice `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
//
|
||||
// Prefer the procedure group `copy`.
|
||||
@builtin
|
||||
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := max(0, min(len(dst), len(src)))
|
||||
@@ -31,6 +40,11 @@ copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
}
|
||||
return n
|
||||
}
|
||||
// `copy_from_string` is a built-in procedure that copies elements from a source slice `src` to a destination string `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
//
|
||||
// Prefer the procedure group `copy`.
|
||||
@builtin
|
||||
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
||||
n := max(0, min(len(dst), len(src)))
|
||||
@@ -39,11 +53,20 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
|
||||
}
|
||||
return n
|
||||
}
|
||||
// `copy` is a built-in procedure that copies elements from a source slice `src` to a destination slice/string `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
@builtin
|
||||
copy :: proc{copy_slice, copy_from_string}
|
||||
|
||||
|
||||
|
||||
// `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value
|
||||
// with the old value, and reducing the length of the dynamic array by 1.
|
||||
//
|
||||
// Note: This is an O(1) operation.
|
||||
// Note: If you the elements to remain in their order, use `ordered_remove`.
|
||||
// Note: If the index is out of bounds, this procedure will panic.
|
||||
@builtin
|
||||
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
|
||||
bounds_check_error_loc(loc, index, len(array))
|
||||
@@ -53,7 +76,11 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
}
|
||||
|
||||
// `ordered_remove` removed the element at the specified `index` whilst keeping the order of the other elements.
|
||||
//
|
||||
// Note: This is an O(N) operation.
|
||||
// Note: If you the elements do not have to remain in their order, prefer `unordered_remove`.
|
||||
// Note: If the index is out of bounds, this procedure will panic.
|
||||
@builtin
|
||||
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
|
||||
bounds_check_error_loc(loc, index, len(array))
|
||||
@@ -63,6 +90,10 @@ ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_locati
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
}
|
||||
|
||||
// `remove_range` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements.
|
||||
//
|
||||
// Note: This is an O(N) operation.
|
||||
// Note: If the range is out of bounds, this procedure will panic.
|
||||
@builtin
|
||||
remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check {
|
||||
slice_expr_error_lo_hi_loc(loc, lo, hi, len(array))
|
||||
@@ -76,15 +107,20 @@ remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_locatio
|
||||
}
|
||||
|
||||
|
||||
// `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
|
||||
//
|
||||
// Note: If the dynamic array has no elements (`len(array) == 0`), this procedure will panic.
|
||||
@builtin
|
||||
pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
|
||||
assert(len(array) > 0, "", loc)
|
||||
assert(len(array) > 0, loc=loc)
|
||||
res = array[len(array)-1]
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
|
||||
// If the operation is not possible, it will return false.
|
||||
@builtin
|
||||
pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
|
||||
if len(array) == 0 {
|
||||
@@ -95,9 +131,12 @@ pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check
|
||||
return
|
||||
}
|
||||
|
||||
// `pop_front` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1.
|
||||
//
|
||||
// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic.
|
||||
@builtin
|
||||
pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
|
||||
assert(len(array) > 0, "", loc)
|
||||
assert(len(array) > 0, loc=loc)
|
||||
res = array[0]
|
||||
if len(array) > 1 {
|
||||
copy(array[0:], array[1:])
|
||||
@@ -106,6 +145,8 @@ pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #
|
||||
return res
|
||||
}
|
||||
|
||||
// `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1.
|
||||
// If the operation is not possible, it will return false.
|
||||
@builtin
|
||||
pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
|
||||
if len(array) == 0 {
|
||||
@@ -120,49 +161,78 @@ pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_
|
||||
}
|
||||
|
||||
|
||||
// `clear` will set the length of a passed dynamic array or map to `0`
|
||||
@builtin
|
||||
clear :: proc{clear_dynamic_array, clear_map}
|
||||
|
||||
// `reserve` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
|
||||
@builtin
|
||||
reserve :: proc{reserve_dynamic_array, reserve_map}
|
||||
|
||||
@builtin
|
||||
non_zero_reserve :: proc{non_zero_reserve_dynamic_array}
|
||||
|
||||
// `resize` will try to resize memory of a passed dynamic array to the requested element count (setting the `len`, and possibly `cap`).
|
||||
@builtin
|
||||
resize :: proc{resize_dynamic_array}
|
||||
|
||||
@builtin
|
||||
non_zero_resize :: proc{non_zero_resize_dynamic_array}
|
||||
|
||||
// Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity.
|
||||
@builtin
|
||||
shrink :: proc{shrink_dynamic_array, shrink_map}
|
||||
|
||||
// `free` will try to free the passed pointer, with the given `allocator` if the allocator supports this operation.
|
||||
@builtin
|
||||
free :: proc{mem_free}
|
||||
|
||||
// `free_all` will try to free/reset all of the memory of the given `allocator` if the allocator supports this operation.
|
||||
@builtin
|
||||
free_all :: proc{mem_free_all}
|
||||
|
||||
|
||||
|
||||
// `delete_string` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer the procedure group `delete`.
|
||||
@builtin
|
||||
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free_with_size(raw_data(str), len(str), allocator, loc)
|
||||
}
|
||||
// `delete_cstring` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer the procedure group `delete`.
|
||||
@builtin
|
||||
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free((^byte)(str), allocator, loc)
|
||||
}
|
||||
// `delete_dynamic_array` will try to free the underlying data of the passed dynamic array, with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer the procedure group `delete`.
|
||||
@builtin
|
||||
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
|
||||
}
|
||||
// `delete_slice` will try to free the underlying data of the passed sliced, with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer the procedure group `delete`.
|
||||
@builtin
|
||||
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
|
||||
}
|
||||
// `delete_map` will try to free the underlying data of the passed map, with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer the procedure group `delete`.
|
||||
@builtin
|
||||
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
|
||||
return map_free_dynamic(transmute(Raw_Map)m, map_info(T), loc)
|
||||
}
|
||||
|
||||
|
||||
// `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer `delete` over the specific `delete_*` procedures where possible.
|
||||
@builtin
|
||||
delete :: proc{
|
||||
delete_string,
|
||||
@@ -170,22 +240,25 @@ delete :: proc{
|
||||
delete_dynamic_array,
|
||||
delete_slice,
|
||||
delete_map,
|
||||
delete_soa_slice,
|
||||
delete_soa_dynamic_array,
|
||||
}
|
||||
|
||||
|
||||
// The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
|
||||
// return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
|
||||
@builtin
|
||||
@(builtin, require_results)
|
||||
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error {
|
||||
return new_aligned(T, align_of(T), allocator, loc)
|
||||
}
|
||||
@(require_results)
|
||||
new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
|
||||
data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return
|
||||
t = (^T)(raw_data(data))
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(builtin, require_results)
|
||||
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
|
||||
t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
|
||||
t = (^T)(raw_data(t_data))
|
||||
@@ -197,6 +270,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
|
||||
|
||||
DEFAULT_RESERVE_CAPACITY :: 16
|
||||
|
||||
@(require_results)
|
||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
make_slice_error_loc(loc, len)
|
||||
data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
|
||||
@@ -207,21 +281,38 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
|
||||
return transmute(T)s, err
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
// `make_slice` allocates and initializes a slice. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_aligned(T, len, align_of(E), allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
// `make_dynamic_array` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
// `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
// `make_dynamic_array_len_cap` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_dynamic_array_error_loc(loc, len, cap)
|
||||
array.allocator = allocator // initialize allocator before just in case it fails to allocate any memory
|
||||
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
|
||||
s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}
|
||||
if data == nil && size_of(E) != 0 {
|
||||
@@ -230,16 +321,25 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
|
||||
array = transmute(T)s
|
||||
return
|
||||
}
|
||||
@(builtin)
|
||||
make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
|
||||
// `make_map` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_map_expr_error_loc(loc, capacity)
|
||||
context.allocator = allocator
|
||||
|
||||
m: T
|
||||
reserve_map(&m, capacity, loc)
|
||||
return m
|
||||
err = reserve_map(&m, capacity, loc)
|
||||
return
|
||||
}
|
||||
@(builtin)
|
||||
// `make_multi_pointer` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// This is "similar" to doing `raw_data(make([]E, len, allocator))`.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_slice_error_loc(loc, len)
|
||||
data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
|
||||
@@ -251,10 +351,11 @@ make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := con
|
||||
}
|
||||
|
||||
|
||||
// The make built-in procedure allocates and initializes a value of type slice, dynamic array, or map (only)
|
||||
// Similar to new, the first argument is a type, not a value. Unlike new, make's return type is the same as the
|
||||
// `make` built-in procedure allocates and initializes a value of type slice, dynamic array, map, or multi-pointer (only).
|
||||
//
|
||||
// Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
|
||||
// type of its argument, not a pointer to it.
|
||||
// Make uses the specified allocator, default is context.allocator, default is context.allocator
|
||||
// Make uses the specified allocator, default is context.allocator.
|
||||
@builtin
|
||||
make :: proc{
|
||||
make_slice,
|
||||
@@ -267,6 +368,9 @@ make :: proc{
|
||||
|
||||
|
||||
|
||||
// `clear_map` will set the length of a passed map to `0`
|
||||
//
|
||||
// Note: Prefer the procedure group `clear`
|
||||
@builtin
|
||||
clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
if m == nil {
|
||||
@@ -275,21 +379,21 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
map_clear_dynamic((^Raw_Map)(m), map_info(T))
|
||||
}
|
||||
|
||||
// `reserve_map` will try to reserve memory of a passed map to the requested element count (setting the `cap`).
|
||||
//
|
||||
// Note: Prefer the procedure group `reserve`
|
||||
@builtin
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
||||
if m != nil {
|
||||
__dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc)
|
||||
}
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
|
||||
}
|
||||
|
||||
/*
|
||||
Shrinks the capacity of a map down to the current length.
|
||||
*/
|
||||
// Shrinks the capacity of a map down to the current length.
|
||||
//
|
||||
// Note: Prefer the procedure group `shrink`
|
||||
@builtin
|
||||
shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool) {
|
||||
shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
|
||||
if m != nil {
|
||||
err := map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
|
||||
did_shrink = err == nil
|
||||
return map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -309,102 +413,150 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
|
||||
_append_elem :: #force_inline proc(array: ^$T/[dynamic]$E, arg: E, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return 0
|
||||
return 0, nil
|
||||
}
|
||||
when size_of(E) == 0 {
|
||||
array := (^Raw_Dynamic_Array)(array)
|
||||
array.len += 1
|
||||
return 1
|
||||
return 1, nil
|
||||
} else {
|
||||
if cap(array) < len(array)+1 {
|
||||
cap := 2 * cap(array) + max(8, 1)
|
||||
_ = reserve(array, cap, loc)
|
||||
|
||||
// do not 'or_return' here as it could be a partial success
|
||||
if should_zero {
|
||||
err = reserve(array, cap, loc)
|
||||
} else {
|
||||
err = non_zero_reserve(array, cap, loc)
|
||||
}
|
||||
}
|
||||
if cap(array)-len(array) > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
assert(data != nil, loc=loc)
|
||||
data[a.len] = arg
|
||||
}
|
||||
a.len += 1
|
||||
return 1
|
||||
return 1, err
|
||||
}
|
||||
return 0
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
return _append_elem(array, arg, true, loc=loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
return _append_elem(array, arg, false, loc=loc)
|
||||
}
|
||||
|
||||
_append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, loc := #caller_location, args: ..E) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
arg_len := len(args)
|
||||
if arg_len <= 0 {
|
||||
return 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
when size_of(E) == 0 {
|
||||
array := (^Raw_Dynamic_Array)(array)
|
||||
array.len += arg_len
|
||||
return arg_len
|
||||
return arg_len, nil
|
||||
} else {
|
||||
if cap(array) < len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve(array, cap, loc)
|
||||
|
||||
// do not 'or_return' here as it could be a partial success
|
||||
if should_zero {
|
||||
err = reserve(array, cap, loc)
|
||||
} else {
|
||||
err = non_zero_reserve(array, cap, loc)
|
||||
}
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
if arg_len > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
assert(data != nil, loc=loc)
|
||||
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
|
||||
}
|
||||
a.len += arg_len
|
||||
}
|
||||
return arg_len
|
||||
return arg_len, err
|
||||
}
|
||||
}
|
||||
|
||||
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
|
||||
@builtin
|
||||
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int {
|
||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
return _append_elems(array, true, loc, ..args)
|
||||
}
|
||||
|
||||
@builtin
|
||||
non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
return _append_elems(array, false, loc, ..args)
|
||||
}
|
||||
|
||||
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
|
||||
_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
args := transmute([]E)arg
|
||||
return append_elems(array=array, args=args, loc=loc)
|
||||
if should_zero {
|
||||
return append_elems(array, ..args, loc=loc)
|
||||
} else {
|
||||
return non_zero_append_elems(array, ..args, loc=loc)
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
return _append_elem_string(array, arg, true, loc)
|
||||
}
|
||||
@builtin
|
||||
non_zero_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
return _append_elem_string(array, arg, false, loc)
|
||||
}
|
||||
|
||||
|
||||
// The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
|
||||
@builtin
|
||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) {
|
||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
n_arg: int
|
||||
for arg in args {
|
||||
n += append(array = array, args = transmute([]E)(arg), loc = loc)
|
||||
n_arg, err = append(array, ..transmute([]E)(arg), loc=loc)
|
||||
n += n_arg
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The append built-in procedure appends elements to the end of a dynamic array
|
||||
@builtin append :: proc{append_elem, append_elems, append_elem_string}
|
||||
@builtin non_zero_append :: proc{non_zero_append_elem, non_zero_append_elems, non_zero_append_elem_string}
|
||||
|
||||
|
||||
@builtin
|
||||
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
|
||||
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return 0
|
||||
return 0, nil
|
||||
}
|
||||
prev_len := len(array)
|
||||
resize(array, len(array)+1)
|
||||
return len(array)-prev_len
|
||||
resize(array, len(array)+1, loc) or_return
|
||||
return len(array)-prev_len, nil
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -412,18 +564,17 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
|
||||
m :: 1
|
||||
new_size := n + m
|
||||
|
||||
if resize(array, new_size, loc) {
|
||||
when size_of(E) != 0 {
|
||||
copy(array[index + m:], array[index:])
|
||||
array[index] = arg
|
||||
}
|
||||
ok = true
|
||||
resize(array, new_size, loc) or_return
|
||||
when size_of(E) != 0 {
|
||||
copy(array[index + m:], array[index:])
|
||||
array[index] = arg
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -436,18 +587,17 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
|
||||
m := len(args)
|
||||
new_size := n + m
|
||||
|
||||
if resize(array, new_size, loc) {
|
||||
when size_of(E) != 0 {
|
||||
copy(array[index + m:], array[index:])
|
||||
copy(array[index:], args)
|
||||
}
|
||||
ok = true
|
||||
resize(array, new_size, loc) or_return
|
||||
when size_of(E) != 0 {
|
||||
copy(array[index + m:], array[index:])
|
||||
copy(array[index:], args)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -460,11 +610,10 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
|
||||
m := len(arg)
|
||||
new_size := n + m
|
||||
|
||||
if resize(array, new_size, loc) {
|
||||
copy(array[index+m:], array[index:])
|
||||
copy(array[index:], arg)
|
||||
ok = true
|
||||
}
|
||||
resize(array, new_size, loc) or_return
|
||||
copy(array[index+m:], array[index:])
|
||||
copy(array[index:], arg)
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -473,11 +622,12 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
|
||||
|
||||
|
||||
@builtin
|
||||
assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
if index < len(array) {
|
||||
array[index] = arg
|
||||
ok = true
|
||||
} else if resize(array, index+1, loc) {
|
||||
} else {
|
||||
resize(array, index+1, loc) or_return
|
||||
array[index] = arg
|
||||
ok = true
|
||||
}
|
||||
@@ -486,11 +636,15 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
|
||||
|
||||
|
||||
@builtin
|
||||
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if index+len(args) < len(array) {
|
||||
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
new_size := index + len(args)
|
||||
if len(args) == 0 {
|
||||
ok = true
|
||||
} else if new_size < len(array) {
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
} else if resize(array, index+1+len(args), loc) {
|
||||
} else {
|
||||
resize(array, new_size, loc) or_return
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
}
|
||||
@@ -499,14 +653,16 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
|
||||
|
||||
|
||||
@builtin
|
||||
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if len(args) == 0 {
|
||||
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
new_size := index + len(arg)
|
||||
if len(arg) == 0 {
|
||||
ok = true
|
||||
} else if index+len(args) < len(array) {
|
||||
copy(array[index:], args)
|
||||
} else if new_size < len(array) {
|
||||
copy(array[index:], arg)
|
||||
ok = true
|
||||
} else if resize(array, index+1+len(args), loc) {
|
||||
copy(array[index:], args)
|
||||
} else {
|
||||
resize(array, new_size, loc) or_return
|
||||
copy(array[index:], arg)
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
@@ -517,6 +673,9 @@ assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
|
||||
|
||||
|
||||
|
||||
// `clear_dynamic_array` will set the length of a passed dynamic array to `0`
|
||||
//
|
||||
// Note: Prefer the procedure group `clear`.
|
||||
@builtin
|
||||
clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
if array != nil {
|
||||
@@ -524,15 +683,17 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
|
||||
//
|
||||
// Note: Prefer the procedure group `reserve`.
|
||||
_reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
|
||||
if array == nil {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
|
||||
if capacity <= a.cap {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.allocator.procedure == nil {
|
||||
@@ -544,26 +705,43 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
||||
new_size := capacity * size_of(E)
|
||||
allocator := a.allocator
|
||||
|
||||
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
|
||||
if new_data == nil || err != nil {
|
||||
return false
|
||||
new_data: []byte
|
||||
if should_zero {
|
||||
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
|
||||
} else {
|
||||
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
|
||||
}
|
||||
if new_data == nil && new_size > 0 {
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
|
||||
a.data = raw_data(new_data)
|
||||
a.cap = capacity
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _reserve_dynamic_array(array, capacity, true, loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _reserve_dynamic_array(array, capacity, false, loc)
|
||||
}
|
||||
|
||||
// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
|
||||
//
|
||||
// Note: Prefer the procedure group `resize`
|
||||
_resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
|
||||
if array == nil {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
|
||||
if length <= a.cap {
|
||||
a.len = max(length, 0)
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.allocator.procedure == nil {
|
||||
@@ -575,15 +753,30 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
|
||||
new_size := length * size_of(E)
|
||||
allocator := a.allocator
|
||||
|
||||
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
|
||||
if new_data == nil || err != nil {
|
||||
return false
|
||||
new_data : []byte
|
||||
if should_zero {
|
||||
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
|
||||
} else {
|
||||
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
|
||||
}
|
||||
if new_data == nil && new_size > 0 {
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
|
||||
a.data = raw_data(new_data)
|
||||
a.len = length
|
||||
a.cap = length
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _resize_dynamic_array(array, length, true, loc=loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _resize_dynamic_array(array, length, false, loc=loc)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -594,8 +787,10 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
|
||||
Returns false if `cap(array) < new_cap`, or the allocator report failure.
|
||||
|
||||
If `len(array) < new_cap`, then `len(array)` will be left unchanged.
|
||||
|
||||
Note: Prefer the procedure group `shrink`
|
||||
*/
|
||||
shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) {
|
||||
shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -615,15 +810,12 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
||||
old_size := a.cap * size_of(E)
|
||||
new_size := new_cap * size_of(E)
|
||||
|
||||
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
new_data := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc) or_return
|
||||
|
||||
a.data = raw_data(new_data)
|
||||
a.len = min(new_cap, a.len)
|
||||
a.cap = new_cap
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
@@ -633,39 +825,6 @@ map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location)
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
incl_elem :: proc(s: ^$S/bit_set[$E; $U], elem: E) {
|
||||
s^ |= {elem}
|
||||
}
|
||||
@builtin
|
||||
incl_elems :: proc(s: ^$S/bit_set[$E; $U], elems: ..E) {
|
||||
for elem in elems {
|
||||
s^ |= {elem}
|
||||
}
|
||||
}
|
||||
@builtin
|
||||
incl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
|
||||
s^ |= other
|
||||
}
|
||||
@builtin
|
||||
excl_elem :: proc(s: ^$S/bit_set[$E; $U], elem: E) {
|
||||
s^ &~= {elem}
|
||||
}
|
||||
@builtin
|
||||
excl_elems :: proc(s: ^$S/bit_set[$E; $U], elems: ..E) {
|
||||
for elem in elems {
|
||||
s^ &~= {elem}
|
||||
}
|
||||
}
|
||||
@builtin
|
||||
excl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
|
||||
s^ &~= other
|
||||
}
|
||||
|
||||
@builtin incl :: proc{incl_elem, incl_elems, incl_bit_set}
|
||||
@builtin excl :: proc{excl_elem, excl_elems, excl_bit_set}
|
||||
|
||||
|
||||
@builtin
|
||||
card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
||||
when size_of(S) == 1 {
|
||||
@@ -706,7 +865,6 @@ assert :: proc(condition: bool, message := "", loc := #caller_location) {
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
panic :: proc(message: string, loc := #caller_location) -> ! {
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
@@ -716,7 +874,6 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
unimplemented :: proc(message := "", loc := #caller_location) -> ! {
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
@@ -1,6 +1,6 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
_ :: intrinsics
|
||||
|
||||
/*
|
||||
@@ -50,6 +50,7 @@ Raw_SOA_Footer_Dynamic_Array :: struct {
|
||||
allocator: Allocator,
|
||||
}
|
||||
|
||||
@(builtin, require_results)
|
||||
raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Slice) {
|
||||
if array == nil {
|
||||
return nil
|
||||
@@ -58,6 +59,7 @@ raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Sl
|
||||
footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr))
|
||||
return
|
||||
}
|
||||
@(builtin, require_results)
|
||||
raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Raw_SOA_Footer_Dynamic_Array) {
|
||||
if array == nil {
|
||||
return nil
|
||||
@@ -78,12 +80,13 @@ raw_soa_footer :: proc{
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
@(builtin, require_results)
|
||||
make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
if length <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
array.allocator = allocator
|
||||
footer := raw_soa_footer(&array)
|
||||
if size_of(E) == 0 {
|
||||
footer.len = length
|
||||
@@ -137,32 +140,31 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(builtin, require_results)
|
||||
make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
return make_soa_aligned(T, length, align_of(E), allocator, loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
@(builtin, require_results)
|
||||
make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
context.allocator = allocator
|
||||
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc)
|
||||
return
|
||||
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) or_return
|
||||
return array, nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
@(builtin, require_results)
|
||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
context.allocator = allocator
|
||||
resize_soa(&array, length, loc)
|
||||
return
|
||||
resize_soa(&array, length, loc) or_return
|
||||
return array, nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
@(builtin, require_results)
|
||||
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
context.allocator = allocator
|
||||
if reserve_soa(&array, capacity, loc) {
|
||||
resize_soa(&array, length, loc)
|
||||
}
|
||||
return
|
||||
reserve_soa(&array, capacity, loc) or_return
|
||||
resize_soa(&array, length, loc) or_return
|
||||
return array, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -176,27 +178,25 @@ make_soa :: proc{
|
||||
|
||||
|
||||
@builtin
|
||||
resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||
resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
|
||||
if array == nil {
|
||||
return false
|
||||
}
|
||||
if !reserve_soa(array, length, loc) {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
reserve_soa(array, length, loc) or_return
|
||||
footer := raw_soa_footer(array)
|
||||
footer.len = length
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
if array == nil {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
|
||||
old_cap := cap(array)
|
||||
if capacity <= old_cap {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
if array.allocator.procedure == nil {
|
||||
@@ -207,7 +207,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
|
||||
footer := raw_soa_footer(array)
|
||||
if size_of(E) == 0 {
|
||||
footer.cap = capacity
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
ti := type_info_of(typeid_of(T))
|
||||
@@ -238,13 +238,10 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
|
||||
|
||||
old_data := (^rawptr)(array)^
|
||||
|
||||
new_bytes, err := array.allocator.procedure(
|
||||
new_bytes := array.allocator.procedure(
|
||||
array.allocator.data, .Alloc, new_size, max_align,
|
||||
nil, old_size, loc,
|
||||
)
|
||||
if new_bytes == nil || err != nil {
|
||||
return false
|
||||
}
|
||||
) or_return
|
||||
new_data := raw_data(new_bytes)
|
||||
|
||||
|
||||
@@ -269,32 +266,29 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
|
||||
new_offset += type.size * capacity
|
||||
}
|
||||
|
||||
_, err = array.allocator.procedure(
|
||||
array.allocator.procedure(
|
||||
array.allocator.data, .Free, 0, max_align,
|
||||
old_data, old_size, loc,
|
||||
)
|
||||
) or_return
|
||||
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
arg_len := 1
|
||||
|
||||
if cap(array) <= len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve_soa(array, cap, loc)
|
||||
if cap(array) <= len(array) + 1 {
|
||||
cap := 2 * cap(array) + 8
|
||||
err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
|
||||
footer := raw_soa_footer(array)
|
||||
|
||||
if size_of(E) > 0 && arg_len > 0 {
|
||||
ti := type_info_of(typeid_of(T))
|
||||
if size_of(E) > 0 && cap(array)-len(array) > 0 {
|
||||
ti := type_info_of(T)
|
||||
ti = type_info_base(ti)
|
||||
si := &ti.variant.(Type_Info_Struct)
|
||||
field_count: uintptr
|
||||
@@ -326,12 +320,14 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat
|
||||
soa_offset += type.size * cap(array)
|
||||
item_offset += type.size
|
||||
}
|
||||
footer.len += 1
|
||||
return 1, err
|
||||
}
|
||||
footer.len += arg_len
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) {
|
||||
append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -343,7 +339,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
|
||||
|
||||
if cap(array) <= len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve_soa(array, cap, loc)
|
||||
err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
|
||||
@@ -380,8 +376,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
|
||||
item_offset += type.size
|
||||
}
|
||||
}
|
||||
|
||||
footer.len += arg_len
|
||||
return arg_len, err
|
||||
}
|
||||
|
||||
|
||||
@@ -393,21 +389,23 @@ append_soa :: proc{
|
||||
}
|
||||
|
||||
|
||||
delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) {
|
||||
delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
when intrinsics.type_struct_field_count(E) != 0 {
|
||||
array := array
|
||||
ptr := (^rawptr)(&array)^
|
||||
free(ptr, allocator, loc)
|
||||
free(ptr, allocator, loc) or_return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) {
|
||||
delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error {
|
||||
when intrinsics.type_struct_field_count(E) != 0 {
|
||||
array := array
|
||||
ptr := (^rawptr)(&array)^
|
||||
footer := raw_soa_footer(&array)
|
||||
free(ptr, footer.allocator, loc)
|
||||
free(ptr, footer.allocator, loc) or_return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -416,3 +414,16 @@ delete_soa :: proc{
|
||||
delete_soa_slice,
|
||||
delete_soa_dynamic_array,
|
||||
}
|
||||
|
||||
|
||||
clear_soa_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) {
|
||||
when intrinsics.type_struct_field_count(E) != 0 {
|
||||
footer := raw_soa_footer(array)
|
||||
footer.len = 0
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
clear_soa :: proc{
|
||||
clear_soa_dynamic_array,
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE)
|
||||
|
||||
Memory_Block :: struct {
|
||||
prev: ^Memory_Block,
|
||||
allocator: Allocator,
|
||||
base: [^]byte,
|
||||
used: uint,
|
||||
capacity: uint,
|
||||
}
|
||||
|
||||
Arena :: struct {
|
||||
backing_allocator: Allocator,
|
||||
curr_block: ^Memory_Block,
|
||||
total_used: uint,
|
||||
total_capacity: uint,
|
||||
minimum_block_size: uint,
|
||||
temp_count: uint,
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||
z, did_overflow := intrinsics.overflow_add(x, y)
|
||||
return z, !did_overflow
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
total_size := uint(capacity + max(alignment, size_of(Memory_Block)))
|
||||
base_offset := uintptr(max(alignment, size_of(Memory_Block)))
|
||||
|
||||
min_alignment: int = max(16, align_of(Memory_Block), int(alignment))
|
||||
data := mem_alloc(int(total_size), min_alignment, allocator, loc) or_return
|
||||
block = (^Memory_Block)(raw_data(data))
|
||||
end := uintptr(raw_data(data)[len(data):])
|
||||
|
||||
block.allocator = allocator
|
||||
block.base = ([^]byte)(uintptr(block) + base_offset)
|
||||
block.capacity = uint(end - uintptr(block.base))
|
||||
|
||||
// Should be zeroed
|
||||
assert(block.used == 0)
|
||||
assert(block.prev == nil)
|
||||
return
|
||||
}
|
||||
|
||||
memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) {
|
||||
if block_to_free != nil {
|
||||
allocator := block_to_free.allocator
|
||||
mem_free(block_to_free, allocator, loc)
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||
alignment_offset := uint(0)
|
||||
ptr := uintptr(block.base[block.used:])
|
||||
mask := alignment-1
|
||||
if ptr & mask != 0 {
|
||||
alignment_offset = uint(alignment - (ptr & mask))
|
||||
}
|
||||
return alignment_offset
|
||||
|
||||
}
|
||||
if block == nil {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
||||
size, size_ok := safe_add(min_size, alignment_offset)
|
||||
if !size_ok {
|
||||
err = .Out_Of_Memory
|
||||
return
|
||||
}
|
||||
|
||||
if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.capacity {
|
||||
err = .Out_Of_Memory
|
||||
return
|
||||
}
|
||||
data = block.base[block.used+alignment_offset:][:min_size]
|
||||
block.used += size
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
align_forward_uint :: proc "contextless" (ptr, align: uint) -> uint {
|
||||
p := ptr
|
||||
modulo := p & (align-1)
|
||||
if modulo != 0 {
|
||||
p += align - modulo
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc)
|
||||
|
||||
size := size
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
needed := align_forward_uint(size, alignment)
|
||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.capacity {
|
||||
if arena.minimum_block_size == 0 {
|
||||
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||
}
|
||||
|
||||
block_size := max(needed, arena.minimum_block_size)
|
||||
|
||||
if arena.backing_allocator.procedure == nil {
|
||||
arena.backing_allocator = default_allocator()
|
||||
}
|
||||
|
||||
new_block := memory_block_alloc(arena.backing_allocator, block_size, alignment, loc) or_return
|
||||
new_block.prev = arena.curr_block
|
||||
arena.curr_block = new_block
|
||||
arena.total_capacity += new_block.capacity
|
||||
}
|
||||
|
||||
prev_used := arena.curr_block.used
|
||||
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
|
||||
arena.total_used += arena.curr_block.used - prev_used
|
||||
return
|
||||
}
|
||||
|
||||
// `arena_init` will initialize the arena with a usuable block.
|
||||
// This procedure is not necessary to use the Arena as the default zero as `arena_alloc` will set things up if necessary
|
||||
@(require_results)
|
||||
arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc := #caller_location) -> Allocator_Error {
|
||||
arena^ = {}
|
||||
arena.backing_allocator = backing_allocator
|
||||
arena.minimum_block_size = max(size, 1<<12) // minimum block size of 4 KiB
|
||||
new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, 0, loc) or_return
|
||||
arena.curr_block = new_block
|
||||
arena.total_capacity += new_block.capacity
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
arena_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
if free_block := arena.curr_block; free_block != nil {
|
||||
arena.curr_block = free_block.prev
|
||||
|
||||
arena.total_capacity -= free_block.capacity
|
||||
memory_block_dealloc(free_block, loc)
|
||||
}
|
||||
}
|
||||
|
||||
// `arena_free_all` will free all but the first memory block, and then reset the memory block
|
||||
arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
for arena.curr_block != nil && arena.curr_block.prev != nil {
|
||||
arena_free_last_memory_block(arena, loc)
|
||||
}
|
||||
|
||||
if arena.curr_block != nil {
|
||||
intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used)
|
||||
arena.curr_block.used = 0
|
||||
}
|
||||
arena.total_used = 0
|
||||
}
|
||||
|
||||
arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
for arena.curr_block != nil {
|
||||
free_block := arena.curr_block
|
||||
arena.curr_block = free_block.prev
|
||||
|
||||
arena.total_capacity -= free_block.capacity
|
||||
memory_block_dealloc(free_block, loc)
|
||||
}
|
||||
arena.total_used = 0
|
||||
arena.total_capacity = 0
|
||||
}
|
||||
|
||||
arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
||||
return Allocator{arena_allocator_proc, arena}
|
||||
}
|
||||
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int,
|
||||
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
arena := (^Arena)(allocator_data)
|
||||
|
||||
size, alignment := uint(size), uint(alignment)
|
||||
old_size := uint(old_size)
|
||||
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
return arena_alloc(arena, size, alignment, location)
|
||||
case .Free:
|
||||
err = .Mode_Not_Implemented
|
||||
case .Free_All:
|
||||
arena_free_all(arena, location)
|
||||
case .Resize, .Resize_Non_Zeroed:
|
||||
old_data := ([^]byte)(old_memory)
|
||||
|
||||
switch {
|
||||
case old_data == nil:
|
||||
return arena_alloc(arena, size, alignment, location)
|
||||
case size == old_size:
|
||||
// return old memory
|
||||
data = old_data[:size]
|
||||
return
|
||||
case size == 0:
|
||||
err = .Mode_Not_Implemented
|
||||
return
|
||||
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
|
||||
// shrink data in-place
|
||||
data = old_data[:size]
|
||||
return
|
||||
}
|
||||
|
||||
new_memory := arena_alloc(arena, size, alignment, location) or_return
|
||||
if new_memory == nil {
|
||||
return
|
||||
}
|
||||
copy(new_memory, old_data[:old_size])
|
||||
return new_memory, nil
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features}
|
||||
}
|
||||
case .Query_Info:
|
||||
err = .Mode_Not_Implemented
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Arena_Temp :: struct {
|
||||
arena: ^Arena,
|
||||
block: ^Memory_Block,
|
||||
used: uint,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
assert(arena != nil, "nil arena", loc)
|
||||
|
||||
temp.arena = arena
|
||||
temp.block = arena.curr_block
|
||||
if arena.curr_block != nil {
|
||||
temp.used = arena.curr_block.used
|
||||
}
|
||||
arena.temp_count += 1
|
||||
return
|
||||
}
|
||||
|
||||
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
if temp.arena == nil {
|
||||
assert(temp.block == nil)
|
||||
assert(temp.used == 0)
|
||||
return
|
||||
}
|
||||
arena := temp.arena
|
||||
|
||||
if temp.block != nil {
|
||||
memory_block_found := false
|
||||
for block := arena.curr_block; block != nil; block = block.prev {
|
||||
if block == temp.block {
|
||||
memory_block_found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !memory_block_found {
|
||||
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
|
||||
}
|
||||
|
||||
for arena.curr_block != temp.block {
|
||||
arena_free_last_memory_block(arena)
|
||||
}
|
||||
|
||||
if block := arena.curr_block; block != nil {
|
||||
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
||||
amount_to_zero := min(block.used-temp.used, block.capacity-block.used)
|
||||
intrinsics.mem_zero(block.base[temp.used:], amount_to_zero)
|
||||
block.used = temp.used
|
||||
}
|
||||
}
|
||||
|
||||
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||
arena.temp_count -= 1
|
||||
}
|
||||
|
||||
// Ignore the use of a `arena_temp_begin` entirely
|
||||
arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
assert(temp.arena != nil, "nil arena", loc)
|
||||
arena := temp.arena
|
||||
|
||||
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||
arena.temp_count -= 1
|
||||
}
|
||||
|
||||
arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package runtime
|
||||
|
||||
when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||
default_allocator_proc :: nil_allocator_proc
|
||||
default_allocator :: nil_allocator
|
||||
} else when ODIN_DEFAULT_TO_PANIC_ALLOCATOR {
|
||||
default_allocator_proc :: panic_allocator_proc
|
||||
default_allocator :: panic_allocator
|
||||
} else {
|
||||
default_allocator :: heap_allocator
|
||||
default_allocator_proc :: heap_allocator_proc
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package runtime
|
||||
|
||||
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
return nil, .Out_Of_Memory
|
||||
case .Free:
|
||||
return nil, .None
|
||||
case .Free_All:
|
||||
return nil, .Mode_Not_Implemented
|
||||
case .Resize, .Resize_Non_Zeroed:
|
||||
if size == 0 {
|
||||
return nil, .None
|
||||
}
|
||||
return nil, .Out_Of_Memory
|
||||
case .Query_Features:
|
||||
return nil, .Mode_Not_Implemented
|
||||
case .Query_Info:
|
||||
return nil, .Mode_Not_Implemented
|
||||
}
|
||||
return nil, .None
|
||||
}
|
||||
|
||||
nil_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = nil_allocator_proc,
|
||||
data = nil,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
if size > 0 {
|
||||
panic("panic allocator, .Alloc called", loc=loc)
|
||||
}
|
||||
case .Alloc_Non_Zeroed:
|
||||
if size > 0 {
|
||||
panic("panic allocator, .Alloc_Non_Zeroed called", loc=loc)
|
||||
}
|
||||
case .Resize:
|
||||
if size > 0 {
|
||||
panic("panic allocator, .Resize called", loc=loc)
|
||||
}
|
||||
case .Resize_Non_Zeroed:
|
||||
if size > 0 {
|
||||
panic("panic allocator, .Alloc_Non_Zeroed called", loc=loc)
|
||||
}
|
||||
case .Free:
|
||||
if old_memory != nil {
|
||||
panic("panic allocator, .Free called", loc=loc)
|
||||
}
|
||||
case .Free_All:
|
||||
panic("panic allocator, .Free_All called", loc=loc)
|
||||
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Query_Features}
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
case .Query_Info:
|
||||
panic("panic allocator, .Query_Info called", loc=loc)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
panic_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = panic_allocator_proc,
|
||||
data = nil,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package runtime
|
||||
|
||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 4 * Megabyte)
|
||||
NO_DEFAULT_TEMP_ALLOCATOR: bool : ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
|
||||
|
||||
when NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
Default_Temp_Allocator :: struct {}
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {}
|
||||
|
||||
default_temp_allocator_proc :: nil_allocator_proc
|
||||
|
||||
@(require_results)
|
||||
default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
return
|
||||
}
|
||||
|
||||
default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
}
|
||||
} else {
|
||||
Default_Temp_Allocator :: struct {
|
||||
arena: Arena,
|
||||
}
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {
|
||||
_ = arena_init(&s.arena, uint(size), backing_allocator)
|
||||
}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
|
||||
if s != nil {
|
||||
arena_destroy(&s.arena)
|
||||
s^ = {}
|
||||
}
|
||||
}
|
||||
|
||||
default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
|
||||
s := (^Default_Temp_Allocator)(allocator_data)
|
||||
return arena_allocator_proc(&s.arena, mode, size, alignment, old_memory, old_size, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
if context.temp_allocator.data == &global_default_temp_allocator_data {
|
||||
temp = arena_temp_begin(&global_default_temp_allocator_data.arena, loc)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
arena_temp_end(temp, loc)
|
||||
}
|
||||
|
||||
@(fini, private)
|
||||
_destroy_temp_allocator_fini :: proc() {
|
||||
default_temp_allocator_destroy(&global_default_temp_allocator_data)
|
||||
}
|
||||
}
|
||||
|
||||
@(deferred_out=default_temp_allocator_temp_end)
|
||||
DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc := #caller_location) -> (Arena_Temp, Source_Code_Location) {
|
||||
if ignore {
|
||||
return {}, loc
|
||||
} else {
|
||||
return default_temp_allocator_temp_begin(loc), loc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = default_temp_allocator_proc,
|
||||
data = allocator,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package runtime
|
||||
|
||||
/*
|
||||
|
||||
package runtime has numerous entities (declarations) which are required by the compiler to function.
|
||||
|
||||
|
||||
## Basic types and calls (and anything they rely on)
|
||||
|
||||
Source_Code_Location
|
||||
Context
|
||||
Allocator
|
||||
Logger
|
||||
|
||||
__init_context
|
||||
_cleanup_runtime
|
||||
|
||||
|
||||
## cstring calls
|
||||
|
||||
cstring_to_string
|
||||
cstring_len
|
||||
|
||||
|
||||
|
||||
## Required when RTTI is enabled (the vast majority of targets)
|
||||
|
||||
Type_Info
|
||||
|
||||
type_table
|
||||
__type_info_of
|
||||
|
||||
|
||||
## Hashing
|
||||
|
||||
default_hasher
|
||||
default_hasher_cstring
|
||||
default_hasher_string
|
||||
|
||||
|
||||
## Pseudo-CRT required procedured due to LLVM but useful in general
|
||||
memset
|
||||
memcpy
|
||||
memove
|
||||
|
||||
|
||||
## Procedures required by the LLVM backend
|
||||
umodti3
|
||||
udivti3
|
||||
modti3
|
||||
divti3
|
||||
fixdfti
|
||||
fixunsdfti
|
||||
fixunsdfdi
|
||||
floattidf
|
||||
floattidf_unsigned
|
||||
truncsfhf2
|
||||
truncdfhf2
|
||||
gnu_h2f_ieee
|
||||
gnu_f2h_ieee
|
||||
extendhfsf2
|
||||
__ashlti3 // wasm specific
|
||||
__multi3 // wasm specific
|
||||
|
||||
|
||||
|
||||
## Required an entry point is defined (i.e. 'main')
|
||||
|
||||
args__
|
||||
|
||||
|
||||
## When -no-crt is defined (and not a wasm target) (mostly due to LLVM)
|
||||
_tls_index
|
||||
_fltused
|
||||
|
||||
|
||||
## Bounds checking procedures (when not disabled with -no-bounds-check)
|
||||
|
||||
bounds_check_error
|
||||
matrix_bounds_check_error
|
||||
slice_expr_error_hi
|
||||
slice_expr_error_lo_hi
|
||||
multi_pointer_slice_expr_error
|
||||
|
||||
|
||||
## Type assertion check
|
||||
|
||||
type_assertion_check
|
||||
type_assertion_check2 // takes in typeid
|
||||
|
||||
|
||||
## Arithmetic
|
||||
|
||||
quo_complex32
|
||||
quo_complex64
|
||||
quo_complex128
|
||||
|
||||
mul_quaternion64
|
||||
mul_quaternion128
|
||||
mul_quaternion256
|
||||
|
||||
quo_quaternion64
|
||||
quo_quaternion128
|
||||
quo_quaternion256
|
||||
|
||||
abs_complex32
|
||||
abs_complex64
|
||||
abs_complex128
|
||||
|
||||
abs_quaternion64
|
||||
abs_quaternion128
|
||||
abs_quaternion256
|
||||
|
||||
|
||||
## Comparison
|
||||
|
||||
memory_equal
|
||||
memory_compare
|
||||
memory_compare_zero
|
||||
|
||||
cstring_eq
|
||||
cstring_ne
|
||||
cstring_lt
|
||||
cstring_gt
|
||||
cstring_le
|
||||
cstring_gt
|
||||
|
||||
string_eq
|
||||
string_ne
|
||||
string_lt
|
||||
string_gt
|
||||
string_le
|
||||
string_gt
|
||||
|
||||
complex32_eq
|
||||
complex32_ne
|
||||
complex64_eq
|
||||
complex64_ne
|
||||
complex128_eq
|
||||
complex128_ne
|
||||
|
||||
quaternion64_eq
|
||||
quaternion64_ne
|
||||
quaternion128_eq
|
||||
quaternion128_ne
|
||||
quaternion256_eq
|
||||
quaternion256_ne
|
||||
|
||||
|
||||
## Map specific calls
|
||||
|
||||
map_seed_from_map_data
|
||||
__dynamic_map_check_grow // static map calls
|
||||
map_insert_hash_dynamic // static map calls
|
||||
__dynamic_map_get // dynamic map calls
|
||||
__dynamic_map_set // dynamic map calls
|
||||
|
||||
|
||||
## Dynamic literals ([dymamic]T and map[K]V) (can be disabled with -no-dynamic-literals)
|
||||
|
||||
__dynamic_array_reserve
|
||||
__dynamic_array_append
|
||||
|
||||
__dynamic_map_reserve
|
||||
|
||||
|
||||
## Objective-C specific
|
||||
|
||||
objc_lookUpClass
|
||||
sel_registerName
|
||||
objc_allocateClassPair
|
||||
|
||||
|
||||
## for-in `string` type
|
||||
|
||||
string_decode_rune
|
||||
string_decode_last_rune // #reverse for
|
||||
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
_ :: intrinsics
|
||||
|
||||
// High performance, cache-friendly, open-addressed Robin Hood hashing hash map
|
||||
@@ -44,7 +44,7 @@ _ :: intrinsics
|
||||
MAP_LOAD_FACTOR :: 75
|
||||
|
||||
// Minimum log2 capacity.
|
||||
MAP_MIN_LOG2_CAPACITY :: 6 // 64 elements
|
||||
MAP_MIN_LOG2_CAPACITY :: 3 // 8 elements
|
||||
|
||||
// Has to be less than 100% though.
|
||||
#assert(MAP_LOAD_FACTOR < 100)
|
||||
@@ -87,7 +87,7 @@ MAP_CACHE_LINE_SIZE :: 1 << MAP_CACHE_LINE_LOG2
|
||||
//
|
||||
// In the optimal case, len(Map_Cell(T){}.data) = 1 so the cell array can be treated
|
||||
// as a regular array of T, which is the case for hashes.
|
||||
Map_Cell :: struct($T: typeid) #align MAP_CACHE_LINE_SIZE {
|
||||
Map_Cell :: struct($T: typeid) #align(MAP_CACHE_LINE_SIZE) {
|
||||
data: [MAP_CACHE_LINE_SIZE / size_of(T) when 0 < size_of(T) && size_of(T) < MAP_CACHE_LINE_SIZE else 1]T,
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T
|
||||
// len() for map
|
||||
@(require_results)
|
||||
map_len :: #force_inline proc "contextless" (m: Raw_Map) -> int {
|
||||
return m.len
|
||||
return int(m.len)
|
||||
}
|
||||
|
||||
// cap() for map
|
||||
@@ -207,8 +207,8 @@ map_load_factor :: #force_inline proc "contextless" (log2_capacity: uintptr) ->
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> int {
|
||||
return int(map_load_factor(map_log2_cap(m)))
|
||||
map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
|
||||
return map_load_factor(map_log2_cap(m))
|
||||
}
|
||||
|
||||
// The data stores the log2 capacity in the lower six bits. This is primarily
|
||||
@@ -251,6 +251,26 @@ map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
|
||||
return (hash != 0) & (hash & TOMBSTONE_MASK == 0)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
map_seed :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
|
||||
return map_seed_from_map_data(map_data(m))
|
||||
}
|
||||
|
||||
// splitmix for uintptr
|
||||
@(require_results)
|
||||
map_seed_from_map_data :: #force_inline proc "contextless" (data: uintptr) -> uintptr {
|
||||
when size_of(uintptr) == size_of(u64) {
|
||||
mix := data + 0x9e3779b97f4a7c15
|
||||
mix = (mix ~ (mix >> 30)) * 0xbf58476d1ce4e5b9
|
||||
mix = (mix ~ (mix >> 27)) * 0x94d049bb133111eb
|
||||
return mix ~ (mix >> 31)
|
||||
} else {
|
||||
mix := data + 0x9e3779b9
|
||||
mix = (mix ~ (mix >> 16)) * 0x21f0aaad
|
||||
mix = (mix ~ (mix >> 15)) * 0x735a2d97
|
||||
return mix ~ (mix >> 15)
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the desired position in the array. This is just index % capacity,
|
||||
// but a procedure as there's some math involved here to recover the capacity.
|
||||
@@ -394,32 +414,24 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
|
||||
tk := map_cell_index_dynamic(sk, info.ks, 1)
|
||||
tv := map_cell_index_dynamic(sv, info.vs, 1)
|
||||
|
||||
|
||||
for {
|
||||
hp := &hs[pos]
|
||||
element_hash := hp^
|
||||
swap_loop: for {
|
||||
element_hash := hs[pos]
|
||||
|
||||
if map_hash_is_empty(element_hash) {
|
||||
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
|
||||
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||
hp^ = h
|
||||
hs[pos] = h
|
||||
|
||||
return result if result != 0 else v_dst
|
||||
}
|
||||
|
||||
if map_hash_is_deleted(element_hash) {
|
||||
break swap_loop
|
||||
}
|
||||
|
||||
if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
|
||||
if map_hash_is_deleted(element_hash) {
|
||||
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
|
||||
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||
hp^ = h
|
||||
|
||||
return result if result != 0 else v_dst
|
||||
}
|
||||
|
||||
if result == 0 {
|
||||
result = map_cell_index_dynamic(vs, info.vs, pos)
|
||||
}
|
||||
@@ -436,8 +448,8 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(tv), size_of_v)
|
||||
|
||||
th := h
|
||||
h = hp^
|
||||
hp^ = th
|
||||
h = hs[pos]
|
||||
hs[pos] = th
|
||||
|
||||
distance = probe_distance
|
||||
}
|
||||
@@ -445,6 +457,103 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
|
||||
pos = (pos + 1) & mask
|
||||
distance += 1
|
||||
}
|
||||
|
||||
// backward shift loop
|
||||
hs[pos] = 0
|
||||
look_ahead: uintptr = 1
|
||||
for {
|
||||
la_pos := (pos + look_ahead) & mask
|
||||
element_hash := hs[la_pos]
|
||||
|
||||
if map_hash_is_deleted(element_hash) {
|
||||
look_ahead += 1
|
||||
hs[la_pos] = 0
|
||||
continue
|
||||
}
|
||||
|
||||
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
|
||||
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
|
||||
|
||||
if map_hash_is_empty(element_hash) {
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||
hs[pos] = h
|
||||
|
||||
return result if result != 0 else v_dst
|
||||
}
|
||||
|
||||
k_src := map_cell_index_dynamic(ks, info.ks, la_pos)
|
||||
v_src := map_cell_index_dynamic(vs, info.vs, la_pos)
|
||||
probe_distance := map_probe_distance(m^, element_hash, la_pos)
|
||||
|
||||
if probe_distance < look_ahead {
|
||||
// probed can be made ideal while placing saved (ending condition)
|
||||
if result == 0 {
|
||||
result = v_dst
|
||||
}
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||
hs[pos] = h
|
||||
|
||||
// This will be an ideal move
|
||||
pos = (la_pos - probe_distance) & mask
|
||||
look_ahead -= probe_distance
|
||||
|
||||
// shift until we hit ideal/empty
|
||||
for probe_distance != 0 {
|
||||
k_dst = map_cell_index_dynamic(ks, info.ks, pos)
|
||||
v_dst = map_cell_index_dynamic(vs, info.vs, pos)
|
||||
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v)
|
||||
hs[pos] = element_hash
|
||||
hs[la_pos] = 0
|
||||
|
||||
pos = (pos + 1) & mask
|
||||
la_pos = (la_pos + 1) & mask
|
||||
look_ahead = (la_pos - pos) & mask
|
||||
element_hash = hs[la_pos]
|
||||
if map_hash_is_empty(element_hash) {
|
||||
return
|
||||
}
|
||||
|
||||
probe_distance = map_probe_distance(m^, element_hash, la_pos)
|
||||
if probe_distance == 0 {
|
||||
return
|
||||
}
|
||||
// can be ideal?
|
||||
if probe_distance < look_ahead {
|
||||
pos = (la_pos - probe_distance) & mask
|
||||
}
|
||||
k_src = map_cell_index_dynamic(ks, info.ks, la_pos)
|
||||
v_src = map_cell_index_dynamic(vs, info.vs, la_pos)
|
||||
}
|
||||
return
|
||||
} else if distance < probe_distance - look_ahead {
|
||||
// shift back probed
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v)
|
||||
hs[pos] = element_hash
|
||||
hs[la_pos] = 0
|
||||
} else {
|
||||
// place saved, save probed
|
||||
if result == 0 {
|
||||
result = v_dst
|
||||
}
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
|
||||
hs[pos] = h
|
||||
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(k_src), size_of_k)
|
||||
intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(v_src), size_of_v)
|
||||
h = hs[la_pos]
|
||||
hs[la_pos] = 0
|
||||
distance = probe_distance - look_ahead
|
||||
}
|
||||
|
||||
pos = (pos + 1) & mask
|
||||
distance += 1
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@@ -503,6 +612,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
|
||||
}
|
||||
k := map_cell_index_dynamic(ks, info.ks, i)
|
||||
v := map_cell_index_dynamic(vs, info.vs, i)
|
||||
hash = info.key_hasher(rawptr(k), map_seed(resized))
|
||||
_ = map_insert_hash_dynamic(&resized, info, hash, k, v)
|
||||
// Only need to do this comparison on each actually added pair, so do not
|
||||
// fold it into the for loop comparator as a micro-optimization.
|
||||
@@ -519,7 +629,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
|
||||
|
||||
|
||||
@(require_results)
|
||||
map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
|
||||
map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
|
||||
if m.allocator.procedure == nil {
|
||||
m.allocator = context.allocator
|
||||
}
|
||||
@@ -529,7 +639,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
|
||||
// map needs to be within the max load factor.
|
||||
log2_capacity := map_log2_cap(m^)
|
||||
if uintptr(m.len) >= map_load_factor(log2_capacity - 1) {
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
shrunk := map_alloc_dynamic(info, log2_capacity - 1, m.allocator) or_return
|
||||
@@ -550,6 +660,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
|
||||
|
||||
k := map_cell_index_dynamic(ks, info.ks, i)
|
||||
v := map_cell_index_dynamic(vs, info.vs, i)
|
||||
hash = info.key_hasher(rawptr(k), map_seed(shrunk))
|
||||
_ = map_insert_hash_dynamic(&shrunk, info, hash, k, v)
|
||||
// Only need to do this comparison on each actually added pair, so do not
|
||||
// fold it into the for loop comparator as a micro-optimization.
|
||||
@@ -561,7 +672,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
|
||||
|
||||
map_free_dynamic(m^, info, loc) or_return
|
||||
m.data = shrunk.data
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@@ -581,7 +692,7 @@ map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
|
||||
if map_len(m) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
h := info.key_hasher(rawptr(k), 0)
|
||||
h := info.key_hasher(rawptr(k), map_seed(m))
|
||||
p := map_desired_position(m, h)
|
||||
d := uintptr(0)
|
||||
c := (uintptr(1) << map_log2_cap(m)) - 1
|
||||
@@ -604,7 +715,7 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
|
||||
if map_len(m) == 0 {
|
||||
return false
|
||||
}
|
||||
h := info.key_hasher(rawptr(k), 0)
|
||||
h := info.key_hasher(rawptr(k), map_seed(m))
|
||||
p := map_desired_position(m, h)
|
||||
d := uintptr(0)
|
||||
c := (uintptr(1) << map_log2_cap(m)) - 1
|
||||
@@ -635,50 +746,19 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
|
||||
m.len -= 1
|
||||
ok = true
|
||||
|
||||
{ // coalesce tombstones
|
||||
// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
|
||||
// TODO(bill): we should do backward shift deletion and not rely on tombstone slots
|
||||
mask := (uintptr(1)<<map_log2_cap(m^)) - 1
|
||||
curr_index := uintptr(index)
|
||||
|
||||
// TODO(bill): determine a good value for this empirically
|
||||
// if we do not implement backward shift deletion
|
||||
PROBE_COUNT :: 8
|
||||
for _ in 0..<PROBE_COUNT {
|
||||
next_index := (curr_index + 1) & mask
|
||||
if next_index == index {
|
||||
// looped around
|
||||
break
|
||||
}
|
||||
|
||||
// if the next element is empty or has zero probe distance, then any lookup
|
||||
// will always fail on the next, so we can clear both of them
|
||||
hash := hs[next_index]
|
||||
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
|
||||
hs[curr_index] = 0
|
||||
return
|
||||
}
|
||||
|
||||
// now the next element will have a probe count of at least one,
|
||||
// so it can use the delete slot instead
|
||||
hs[curr_index] = hs[next_index]
|
||||
|
||||
mem_copy_non_overlapping(
|
||||
rawptr(map_cell_index_dynamic(ks, info.ks, curr_index)),
|
||||
rawptr(map_cell_index_dynamic(ks, info.ks, next_index)),
|
||||
int(info.ks.size_of_type),
|
||||
)
|
||||
mem_copy_non_overlapping(
|
||||
rawptr(map_cell_index_dynamic(vs, info.vs, curr_index)),
|
||||
rawptr(map_cell_index_dynamic(vs, info.vs, next_index)),
|
||||
int(info.vs.size_of_type),
|
||||
)
|
||||
|
||||
curr_index = next_index
|
||||
}
|
||||
mask := (uintptr(1)<<map_log2_cap(m^)) - 1
|
||||
curr_index := uintptr(index)
|
||||
next_index := (curr_index + 1) & mask
|
||||
|
||||
// if the next element is empty or has zero probe distance, then any lookup
|
||||
// will always fail on the next, so we can clear both of them
|
||||
hash := hs[next_index]
|
||||
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
|
||||
hs[curr_index] = 0
|
||||
} else {
|
||||
hs[curr_index] |= TOMBSTONE_MASK
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -711,7 +791,7 @@ map_get :: proc "contextless" (m: $T/map[$K]$V, key: K) -> (stored_key: K, store
|
||||
info := intrinsics.type_map_info(T)
|
||||
key := key
|
||||
|
||||
h := info.key_hasher(&key, 0)
|
||||
h := info.key_hasher(&key, map_seed(rm))
|
||||
pos := map_desired_position(rm, h)
|
||||
distance := uintptr(0)
|
||||
mask := (uintptr(1) << map_log2_cap(rm)) - 1
|
||||
@@ -762,15 +842,15 @@ __dynamic_map_get :: proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info:
|
||||
}
|
||||
|
||||
// IMPORTANT: USED WITHIN THE COMPILER
|
||||
__dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
|
||||
__dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (err: Allocator_Error, has_grown: bool) {
|
||||
if m.len >= map_resize_threshold(m^) {
|
||||
return map_grow_dynamic(m, info, loc)
|
||||
return map_grow_dynamic(m, info, loc), true
|
||||
}
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
|
||||
__dynamic_map_set_without_hash :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key, value: rawptr, loc := #caller_location) -> rawptr {
|
||||
return __dynamic_map_set(m, info, info.key_hasher(key, 0), key, value, loc)
|
||||
return __dynamic_map_set(m, info, info.key_hasher(key, map_seed(m^)), key, value, loc)
|
||||
}
|
||||
|
||||
|
||||
@@ -781,9 +861,14 @@ __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_In
|
||||
return found
|
||||
}
|
||||
|
||||
if __dynamic_map_check_grow(m, info, loc) != nil {
|
||||
hash := hash
|
||||
err, has_grown := __dynamic_map_check_grow(m, info, loc)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if has_grown {
|
||||
hash = info.key_hasher(key, map_seed(m^))
|
||||
}
|
||||
|
||||
result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
|
||||
m.len += 1
|
||||
@@ -0,0 +1,59 @@
|
||||
//+private
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
//+no-instrumentation
|
||||
package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
when ODIN_BUILD_MODE == .Dynamic {
|
||||
@(link_name="_odin_entry_point", linkage="strong", require/*, link_section=".init"*/)
|
||||
_odin_entry_point :: proc "c" () {
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
}
|
||||
@(link_name="_odin_exit_point", linkage="strong", require/*, link_section=".fini"*/)
|
||||
_odin_exit_point :: proc "c" () {
|
||||
context = default_context()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
}
|
||||
@(link_name="main", linkage="strong", require)
|
||||
main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
|
||||
return 0
|
||||
}
|
||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
when ODIN_NO_CRT {
|
||||
// NOTE(flysand): We need to start from assembly because we need
|
||||
// to retrieve argc and argv from the stack
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@require foreign import entry "entry_unix_no_crt_amd64.asm"
|
||||
SYS_exit :: 60
|
||||
} else when ODIN_ARCH == .i386 {
|
||||
@require foreign import entry "entry_unix_no_crt_i386.asm"
|
||||
SYS_exit :: 1
|
||||
} else when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
|
||||
@require foreign import entry "entry_unix_no_crt_darwin_arm64.asm"
|
||||
SYS_exit :: 1
|
||||
}
|
||||
@(link_name="_start_odin", linkage="strong", require)
|
||||
_start_odin :: proc "c" (argc: i32, argv: [^]cstring) -> ! {
|
||||
args__ = argv[:argc]
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
intrinsics.syscall(SYS_exit, 0)
|
||||
unreachable()
|
||||
}
|
||||
} else {
|
||||
@(link_name="main", linkage="strong", require)
|
||||
main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
|
||||
args__ = argv[:argc]
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
bits 64
|
||||
|
||||
extern _start_odin
|
||||
global _start
|
||||
|
||||
section .text
|
||||
|
||||
;; Entry point for programs that specify -no-crt option
|
||||
;; This entry point should be compatible with dynamic loaders on linux
|
||||
;; The parameters the dynamic loader passes to the _start function:
|
||||
;; RDX = pointer to atexit function
|
||||
;; The stack layout is as follows:
|
||||
;; +-------------------+
|
||||
;; NULL
|
||||
;; +-------------------+
|
||||
;; envp[m]
|
||||
;; +-------------------+
|
||||
;; ...
|
||||
;; +-------------------+
|
||||
;; envp[0]
|
||||
;; +-------------------+
|
||||
;; NULL
|
||||
;; +-------------------+
|
||||
;; argv[n]
|
||||
;; +-------------------+
|
||||
;; ...
|
||||
;; +-------------------+
|
||||
;; argv[0]
|
||||
;; +-------------------+
|
||||
;; argc
|
||||
;; +-------------------+ <------ RSP
|
||||
;;
|
||||
_start:
|
||||
;; Mark stack frame as the top of the stack
|
||||
xor rbp, rbp
|
||||
;; Load argc into 1st param reg, argv into 2nd param reg
|
||||
pop rdi
|
||||
mov rdx, rsi
|
||||
;; Align stack pointer down to 16-bytes (sysv calling convention)
|
||||
and rsp, -16
|
||||
;; Call into odin entry point
|
||||
call _start_odin
|
||||
jmp $$
|
||||
@@ -0,0 +1,20 @@
|
||||
.section __TEXT,__text
|
||||
|
||||
; NOTE(laytan): this should ideally be the -minimum-os-version flag but there is no nice way of preprocessing assembly in Odin.
|
||||
; 10 seems to be the lowest it goes and I don't see it mess with any targeted os version so this seems fine.
|
||||
.build_version macos, 10, 0
|
||||
|
||||
.extern __start_odin
|
||||
|
||||
.global _main
|
||||
.align 2
|
||||
_main:
|
||||
mov x5, sp ; use x5 as the stack pointer
|
||||
|
||||
str x0, [x5] ; get argc into x0 (kernel passes 32-bit int argc as 64-bits on stack to keep alignment)
|
||||
str x1, [x5, #8] ; get argv into x1
|
||||
|
||||
and sp, x5, #~15 ; force 16-byte alignment of the stack
|
||||
|
||||
bl __start_odin ; call into Odin entry point
|
||||
ret ; should never get here
|
||||
@@ -0,0 +1,18 @@
|
||||
bits 32
|
||||
|
||||
extern _start_odin
|
||||
global _start
|
||||
|
||||
section .text
|
||||
|
||||
;; NOTE(flysand): For description see the corresponding *_amd64.asm file
|
||||
;; also I didn't test this on x86-32
|
||||
_start:
|
||||
xor ebp, rbp
|
||||
pop ecx
|
||||
mov eax, esp
|
||||
and esp, -16
|
||||
push eax
|
||||
push ecx
|
||||
call _start_odin
|
||||
jmp $$
|
||||
@@ -1,8 +1,9 @@
|
||||
//+private
|
||||
//+build wasm32, wasm64
|
||||
//+build wasm32, wasm64p32
|
||||
//+no-instrumentation
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
@(link_name="_start", linkage="strong", require, export)
|
||||
@@ -1,12 +1,13 @@
|
||||
//+private
|
||||
//+build windows
|
||||
//+no-instrumentation
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
when ODIN_BUILD_MODE == .Dynamic {
|
||||
@(link_name="DllMain", linkage="strong", require)
|
||||
DllMain :: proc "stdcall" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 {
|
||||
DllMain :: proc "system" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 {
|
||||
context = default_context()
|
||||
|
||||
// Populate Windows DLL-specific global
|
||||
@@ -28,7 +29,7 @@ when ODIN_BUILD_MODE == .Dynamic {
|
||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
when ODIN_ARCH == .i386 || ODIN_NO_CRT {
|
||||
@(link_name="mainCRTStartup", linkage="strong", require)
|
||||
mainCRTStartup :: proc "stdcall" () -> i32 {
|
||||
mainCRTStartup :: proc "system" () -> i32 {
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
@@ -1,5 +1,6 @@
|
||||
package runtime
|
||||
|
||||
@(no_instrumentation)
|
||||
bounds_trap :: proc "contextless" () -> ! {
|
||||
when ODIN_OS == .Windows {
|
||||
windows_trap_array_bounds()
|
||||
@@ -8,6 +9,7 @@ bounds_trap :: proc "contextless" () -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
@(no_instrumentation)
|
||||
type_assertion_trap :: proc "contextless" () -> ! {
|
||||
when ODIN_OS == .Windows {
|
||||
windows_trap_type_assertion()
|
||||
@@ -21,8 +23,8 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
||||
if uint(index) < uint(count) {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Index ")
|
||||
print_i64(i64(index))
|
||||
@@ -34,6 +36,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
||||
handle_error(file, line, column, index, count)
|
||||
}
|
||||
|
||||
@(no_instrumentation)
|
||||
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid slice indices ")
|
||||
@@ -46,6 +49,7 @@ slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, h
|
||||
bounds_trap()
|
||||
}
|
||||
|
||||
@(no_instrumentation)
|
||||
multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid slice indices ")
|
||||
@@ -82,8 +86,8 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid dynamic array indices ")
|
||||
print_i64(i64(low))
|
||||
@@ -103,8 +107,8 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
|
||||
uint(column_index) < uint(column_count) {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Matrix indices [")
|
||||
print_i64(i64(row_index))
|
||||
@@ -122,13 +126,13 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
|
||||
}
|
||||
|
||||
|
||||
when ODIN_DISALLOW_RTTI {
|
||||
when ODIN_NO_RTTI {
|
||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion\n")
|
||||
type_assertion_trap()
|
||||
@@ -140,8 +144,8 @@ when ODIN_DISALLOW_RTTI {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion\n")
|
||||
type_assertion_trap()
|
||||
@@ -153,8 +157,8 @@ when ODIN_DISALLOW_RTTI {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
@@ -198,8 +202,8 @@ when ODIN_DISALLOW_RTTI {
|
||||
return id
|
||||
}
|
||||
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) -> ! {
|
||||
|
||||
actual := variant_type(from, from_data)
|
||||
|
||||
@@ -224,8 +228,8 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
|
||||
if 0 <= len {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) -> ! {
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid slice length for make: ")
|
||||
print_i64(i64(len))
|
||||
@@ -235,12 +239,12 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
|
||||
handle_error(loc, len)
|
||||
}
|
||||
|
||||
make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, len, cap: int) {
|
||||
make_dynamic_array_error_loc :: #force_inline proc "contextless" (loc := #caller_location, len, cap: int) {
|
||||
if 0 <= len && len <= cap {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) -> ! {
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid dynamic array parameters for make: ")
|
||||
print_i64(i64(len))
|
||||
@@ -256,8 +260,8 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
|
||||
if 0 <= cap {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
|
||||
@(cold, no_instrumentation)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) -> ! {
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid map capacity for make: ")
|
||||
print_i64(i64(cap))
|
||||
@@ -271,18 +275,18 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
|
||||
|
||||
|
||||
|
||||
bounds_check_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, index, count: int) {
|
||||
bounds_check_error(file_path, line, column, index, count)
|
||||
bounds_check_error_loc :: #force_inline proc "contextless" (loc := #caller_location, index, count: int) {
|
||||
bounds_check_error(loc.file_path, loc.line, loc.column, index, count)
|
||||
}
|
||||
|
||||
slice_expr_error_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, hi: int, len: int) {
|
||||
slice_expr_error_hi(file_path, line, column, hi, len)
|
||||
slice_expr_error_hi_loc :: #force_inline proc "contextless" (loc := #caller_location, hi: int, len: int) {
|
||||
slice_expr_error_hi(loc.file_path, loc.line, loc.column, hi, len)
|
||||
}
|
||||
|
||||
slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) {
|
||||
slice_expr_error_lo_hi(file_path, line, column, lo, hi, len)
|
||||
slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (loc := #caller_location, lo, hi: int, len: int) {
|
||||
slice_expr_error_lo_hi(loc.file_path, loc.line, loc.column, lo, hi, len)
|
||||
}
|
||||
|
||||
dynamic_array_expr_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, low, high, max: int) {
|
||||
dynamic_array_expr_error(file_path, line, column, low, high, max)
|
||||
dynamic_array_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_location, low, high, max: int) {
|
||||
dynamic_array_expr_error(loc.file_path, loc.line, loc.column, low, high, max)
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
heap_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = heap_allocator_proc,
|
||||
data = nil,
|
||||
}
|
||||
}
|
||||
|
||||
heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
//
|
||||
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
|
||||
// Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
|
||||
// padding. We also store the original pointer returned by heap_alloc right before
|
||||
// the pointer we return to the user.
|
||||
//
|
||||
|
||||
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil, zero_memory := true) -> ([]byte, Allocator_Error) {
|
||||
a := max(alignment, align_of(rawptr))
|
||||
space := size + a - 1
|
||||
|
||||
allocated_mem: rawptr
|
||||
if old_ptr != nil {
|
||||
original_old_ptr := ([^]rawptr)(old_ptr)[-1]
|
||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
||||
} else {
|
||||
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
|
||||
}
|
||||
aligned_mem := rawptr(([^]u8)(allocated_mem)[size_of(rawptr):])
|
||||
|
||||
ptr := uintptr(aligned_mem)
|
||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||
diff := int(aligned_ptr - ptr)
|
||||
if (size + diff) > space || allocated_mem == nil {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
||||
aligned_mem = rawptr(aligned_ptr)
|
||||
([^]rawptr)(aligned_mem)[-1] = allocated_mem
|
||||
|
||||
return byte_slice(aligned_mem, size), nil
|
||||
}
|
||||
|
||||
aligned_free :: proc(p: rawptr) {
|
||||
if p != nil {
|
||||
heap_free(([^]rawptr)(p)[-1])
|
||||
}
|
||||
}
|
||||
|
||||
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int, zero_memory := true) -> (new_memory: []byte, err: Allocator_Error) {
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
new_memory = aligned_alloc(new_size, new_alignment, p, zero_memory) or_return
|
||||
|
||||
// NOTE: heap_resize does not zero the new memory, so we do it
|
||||
if zero_memory && new_size > old_size {
|
||||
new_region := raw_data(new_memory[old_size:])
|
||||
intrinsics.mem_zero(new_region, new_size - old_size)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
return aligned_alloc(size, alignment, nil, mode == .Alloc)
|
||||
|
||||
case .Free:
|
||||
aligned_free(old_memory)
|
||||
|
||||
case .Free_All:
|
||||
return nil, .Mode_Not_Implemented
|
||||
|
||||
case .Resize, .Resize_Non_Zeroed:
|
||||
if old_memory == nil {
|
||||
return aligned_alloc(size, alignment, nil, mode == .Resize)
|
||||
}
|
||||
return aligned_resize(old_memory, old_size, size, alignment, mode == .Resize)
|
||||
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Resize_Non_Zeroed, .Query_Features}
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
case .Query_Info:
|
||||
return nil, .Mode_Not_Implemented
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||
return _heap_alloc(size, zero_memory)
|
||||
}
|
||||
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
return _heap_resize(ptr, new_size)
|
||||
}
|
||||
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
_heap_free(ptr)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//+build js, wasi, freestanding, essence
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||
unimplemented("base:runtime 'heap_alloc' procedure is not supported on this platform")
|
||||
}
|
||||
|
||||
_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
unimplemented("base:runtime 'heap_resize' procedure is not supported on this platform")
|
||||
}
|
||||
|
||||
_heap_free :: proc(ptr: rawptr) {
|
||||
unimplemented("base:runtime 'heap_free' procedure is not supported on this platform")
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---
|
||||
}
|
||||
|
||||
_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
if zero_memory {
|
||||
return _unix_calloc(1, size)
|
||||
} else {
|
||||
return _unix_malloc(size)
|
||||
}
|
||||
}
|
||||
|
||||
_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||
// POSIX platforms. Ensure your caller takes this into account.
|
||||
return _unix_realloc(ptr, new_size)
|
||||
}
|
||||
|
||||
_heap_free :: proc(ptr: rawptr) {
|
||||
_unix_free(ptr)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package runtime
|
||||
|
||||
foreign import kernel32 "system:Kernel32.lib"
|
||||
|
||||
@(private="file")
|
||||
@(default_calling_convention="system")
|
||||
foreign kernel32 {
|
||||
// NOTE(bill): The types are not using the standard names (e.g. DWORD and LPVOID) to just minimizing the dependency
|
||||
|
||||
// default_allocator
|
||||
GetProcessHeap :: proc() -> rawptr ---
|
||||
HeapAlloc :: proc(hHeap: rawptr, dwFlags: u32, dwBytes: uint) -> rawptr ---
|
||||
HeapReAlloc :: proc(hHeap: rawptr, dwFlags: u32, lpMem: rawptr, dwBytes: uint) -> rawptr ---
|
||||
HeapFree :: proc(hHeap: rawptr, dwFlags: u32, lpMem: rawptr) -> b32 ---
|
||||
}
|
||||
|
||||
_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||
HEAP_ZERO_MEMORY :: 0x00000008
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY if zero_memory else 0, uint(size))
|
||||
}
|
||||
_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
if new_size == 0 {
|
||||
_heap_free(ptr)
|
||||
return nil
|
||||
}
|
||||
if ptr == nil {
|
||||
return _heap_alloc(new_size)
|
||||
}
|
||||
|
||||
HEAP_ZERO_MEMORY :: 0x00000008
|
||||
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size))
|
||||
}
|
||||
_heap_free :: proc(ptr: rawptr) {
|
||||
if ptr == nil {
|
||||
return
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, ptr)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
@(private="file")
|
||||
IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64
|
||||
IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
|
||||
|
||||
@(private)
|
||||
RUNTIME_LINKAGE :: "strong" when (
|
||||
@@ -11,7 +11,10 @@ RUNTIME_LINKAGE :: "strong" when (
|
||||
ODIN_BUILD_MODE == .Dynamic ||
|
||||
!ODIN_NO_CRT) &&
|
||||
!IS_WASM) else "internal"
|
||||
RUNTIME_REQUIRE :: true
|
||||
RUNTIME_REQUIRE :: !ODIN_TILDE
|
||||
|
||||
@(private)
|
||||
__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16
|
||||
|
||||
|
||||
@(private)
|
||||
@@ -19,50 +22,6 @@ byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byt
|
||||
return ([^]byte)(data)[:max(len, 0)]
|
||||
}
|
||||
|
||||
bswap_16 :: proc "contextless" (x: u16) -> u16 {
|
||||
return x>>8 | x<<8
|
||||
}
|
||||
|
||||
bswap_32 :: proc "contextless" (x: u32) -> u32 {
|
||||
return x>>24 | (x>>8)&0xff00 | (x<<8)&0xff0000 | x<<24
|
||||
}
|
||||
|
||||
bswap_64 :: proc "contextless" (x: u64) -> u64 {
|
||||
z := x
|
||||
z = (z & 0x00000000ffffffff) << 32 | (z & 0xffffffff00000000) >> 32
|
||||
z = (z & 0x0000ffff0000ffff) << 16 | (z & 0xffff0000ffff0000) >> 16
|
||||
z = (z & 0x00ff00ff00ff00ff) << 8 | (z & 0xff00ff00ff00ff00) >> 8
|
||||
return z
|
||||
}
|
||||
|
||||
bswap_128 :: proc "contextless" (x: u128) -> u128 {
|
||||
z := transmute([4]u32)x
|
||||
z[0], z[3] = bswap_32(z[3]), bswap_32(z[0])
|
||||
z[1], z[2] = bswap_32(z[2]), bswap_32(z[1])
|
||||
return transmute(u128)z
|
||||
}
|
||||
|
||||
bswap_f16 :: proc "contextless" (f: f16) -> f16 {
|
||||
x := transmute(u16)f
|
||||
z := bswap_16(x)
|
||||
return transmute(f16)z
|
||||
|
||||
}
|
||||
|
||||
bswap_f32 :: proc "contextless" (f: f32) -> f32 {
|
||||
x := transmute(u32)f
|
||||
z := bswap_32(x)
|
||||
return transmute(f32)z
|
||||
|
||||
}
|
||||
|
||||
bswap_f64 :: proc "contextless" (f: f64) -> f64 {
|
||||
x := transmute(u64)f
|
||||
z := bswap_64(x)
|
||||
return transmute(f64)z
|
||||
}
|
||||
|
||||
|
||||
is_power_of_two_int :: #force_inline proc(x: int) -> bool {
|
||||
if x <= 0 {
|
||||
return false
|
||||
@@ -184,32 +143,52 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
|
||||
return
|
||||
}
|
||||
|
||||
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
_mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
if allocator.procedure == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if new_size == 0 {
|
||||
if ptr != nil {
|
||||
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
|
||||
return nil, err
|
||||
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
|
||||
return
|
||||
}
|
||||
return nil, nil
|
||||
return
|
||||
} else if ptr == nil {
|
||||
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
|
||||
if should_zero {
|
||||
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
|
||||
} else {
|
||||
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
|
||||
}
|
||||
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
|
||||
return ([^]byte)(ptr)[:old_size], nil
|
||||
data = ([^]byte)(ptr)[:old_size]
|
||||
return
|
||||
}
|
||||
|
||||
data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
|
||||
if should_zero {
|
||||
data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
|
||||
} else {
|
||||
data, err = allocator.procedure(allocator.data, .Resize_Non_Zeroed, new_size, alignment, ptr, old_size, loc)
|
||||
}
|
||||
if err == .Mode_Not_Implemented {
|
||||
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
|
||||
if should_zero {
|
||||
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
|
||||
} else {
|
||||
data, err = allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
|
||||
}
|
||||
if err != nil {
|
||||
return data, err
|
||||
return
|
||||
}
|
||||
copy(data, ([^]byte)(ptr)[:old_size])
|
||||
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
|
||||
}
|
||||
return data, err
|
||||
return
|
||||
}
|
||||
|
||||
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
return _mem_resize(ptr, old_size, new_size, alignment, allocator, true, loc)
|
||||
}
|
||||
non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc)
|
||||
}
|
||||
|
||||
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
@@ -217,13 +196,21 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
case n == 0: return true
|
||||
case x == y: return true
|
||||
}
|
||||
|
||||
a, b := ([^]byte)(x), ([^]byte)(y)
|
||||
length := uint(n)
|
||||
|
||||
for i := uint(0); i < length; i += 1 {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
/*
|
||||
|
||||
when size_of(uint) == 8 {
|
||||
if word_length := length >> 3; word_length != 0 {
|
||||
for i in 0..<word_length {
|
||||
for _ in 0..<word_length {
|
||||
if intrinsics.unaligned_load((^u64)(a)) != intrinsics.unaligned_load((^u64)(b)) {
|
||||
return false
|
||||
}
|
||||
@@ -254,7 +241,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
return true
|
||||
} else {
|
||||
if word_length := length >> 2; word_length != 0 {
|
||||
for i in 0..<word_length {
|
||||
for _ in 0..<word_length {
|
||||
if intrinsics.unaligned_load((^u32)(a)) != intrinsics.unaligned_load((^u32)(b)) {
|
||||
return false
|
||||
}
|
||||
@@ -275,6 +262,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
|
||||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
|
||||
@@ -400,6 +388,48 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
}
|
||||
|
||||
|
||||
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
|
||||
x := ([^]byte)(lhs)
|
||||
y := ([^]byte)(rhs)
|
||||
if x == y {
|
||||
return true
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return false
|
||||
}
|
||||
xn := cstring_len(lhs)
|
||||
yn := cstring_len(rhs)
|
||||
if xn != yn {
|
||||
return false
|
||||
}
|
||||
return #force_inline memory_equal(x, y, xn)
|
||||
}
|
||||
|
||||
cstring_cmp :: proc "contextless" (lhs, rhs: cstring) -> int {
|
||||
x := ([^]byte)(lhs)
|
||||
y := ([^]byte)(rhs)
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return -1 if x == nil else +1
|
||||
}
|
||||
xn := cstring_len(lhs)
|
||||
yn := cstring_len(rhs)
|
||||
ret := memory_compare(x, y, min(xn, yn))
|
||||
if ret == 0 && xn != yn {
|
||||
return -1 if xn < yn else +1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
cstring_ne :: #force_inline proc "contextless" (a, b: cstring) -> bool { return !cstring_eq(a, b) }
|
||||
cstring_lt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) < 0 }
|
||||
cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) > 0 }
|
||||
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
|
||||
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
|
||||
|
||||
|
||||
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
|
||||
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }
|
||||
|
||||
@@ -499,46 +529,73 @@ string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int
|
||||
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4
|
||||
}
|
||||
|
||||
abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 {
|
||||
return -x if x < 0 else x
|
||||
}
|
||||
abs_f32 :: #force_inline proc "contextless" (x: f32) -> f32 {
|
||||
return -x if x < 0 else x
|
||||
}
|
||||
abs_f64 :: #force_inline proc "contextless" (x: f64) -> f64 {
|
||||
return -x if x < 0 else x
|
||||
}
|
||||
string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
|
||||
RUNE_ERROR :: '\ufffd'
|
||||
RUNE_SELF :: 0x80
|
||||
UTF_MAX :: 4
|
||||
|
||||
min_f16 :: #force_inline proc "contextless" (a, b: f16) -> f16 {
|
||||
return a if a < b else b
|
||||
}
|
||||
min_f32 :: #force_inline proc "contextless" (a, b: f32) -> f32 {
|
||||
return a if a < b else b
|
||||
}
|
||||
min_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 {
|
||||
return a if a < b else b
|
||||
}
|
||||
max_f16 :: #force_inline proc "contextless" (a, b: f16) -> f16 {
|
||||
return a if a > b else b
|
||||
}
|
||||
max_f32 :: #force_inline proc "contextless" (a, b: f32) -> f32 {
|
||||
return a if a > b else b
|
||||
}
|
||||
max_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 {
|
||||
return a if a > b else b
|
||||
r: rune
|
||||
size: int
|
||||
start, end, limit: int
|
||||
|
||||
end = len(s)
|
||||
if end == 0 {
|
||||
return RUNE_ERROR, 0
|
||||
}
|
||||
start = end-1
|
||||
r = rune(s[start])
|
||||
if r < RUNE_SELF {
|
||||
return r, 1
|
||||
}
|
||||
|
||||
limit = max(end - UTF_MAX, 0)
|
||||
|
||||
for start-=1; start >= limit; start-=1 {
|
||||
if (s[start] & 0xc0) != RUNE_SELF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
start = max(start, 0)
|
||||
r, size = string_decode_rune(s[start:end])
|
||||
if start+size != end {
|
||||
return RUNE_ERROR, 1
|
||||
}
|
||||
return r, size
|
||||
}
|
||||
|
||||
abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 {
|
||||
r, i := real(x), imag(x)
|
||||
return f16(intrinsics.sqrt(f32(r*r + i*i)))
|
||||
p, q := abs(real(x)), abs(imag(x))
|
||||
if p < q {
|
||||
p, q = q, p
|
||||
}
|
||||
if p == 0 {
|
||||
return 0
|
||||
}
|
||||
q = q / p
|
||||
return p * f16(intrinsics.sqrt(f32(1 + q*q)))
|
||||
}
|
||||
abs_complex64 :: #force_inline proc "contextless" (x: complex64) -> f32 {
|
||||
r, i := real(x), imag(x)
|
||||
return intrinsics.sqrt(r*r + i*i)
|
||||
p, q := abs(real(x)), abs(imag(x))
|
||||
if p < q {
|
||||
p, q = q, p
|
||||
}
|
||||
if p == 0 {
|
||||
return 0
|
||||
}
|
||||
q = q / p
|
||||
return p * intrinsics.sqrt(1 + q*q)
|
||||
}
|
||||
abs_complex128 :: #force_inline proc "contextless" (x: complex128) -> f64 {
|
||||
r, i := real(x), imag(x)
|
||||
return intrinsics.sqrt(r*r + i*i)
|
||||
p, q := abs(real(x)), abs(imag(x))
|
||||
if p < q {
|
||||
p, q = q, p
|
||||
}
|
||||
if p == 0 {
|
||||
return 0
|
||||
}
|
||||
q = q / p
|
||||
return p * intrinsics.sqrt(1 + q*q)
|
||||
}
|
||||
abs_quaternion64 :: #force_inline proc "contextless" (x: quaternion64) -> f16 {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x)
|
||||
@@ -618,7 +675,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||
|
||||
return quaternion(t0, t1, t2, t3)
|
||||
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||
}
|
||||
|
||||
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
@@ -630,7 +687,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||
|
||||
return quaternion(t0, t1, t2, t3)
|
||||
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||
}
|
||||
|
||||
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
@@ -642,7 +699,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||
|
||||
return quaternion(t0, t1, t2, t3)
|
||||
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||
}
|
||||
|
||||
quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||
@@ -656,7 +713,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||
|
||||
return quaternion(t0, t1, t2, t3)
|
||||
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||
}
|
||||
|
||||
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
@@ -670,7 +727,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||
|
||||
return quaternion(t0, t1, t2, t3)
|
||||
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||
}
|
||||
|
||||
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
@@ -684,11 +741,11 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||
|
||||
return quaternion(t0, t1, t2, t3)
|
||||
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||
}
|
||||
|
||||
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
truncsfhf2 :: proc "c" (value: f32) -> __float16 {
|
||||
v: struct #raw_union { i: u32, f: f32 }
|
||||
i, s, e, m: i32
|
||||
|
||||
@@ -702,7 +759,7 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
|
||||
if e <= 0 {
|
||||
if e < -10 {
|
||||
return u16(s)
|
||||
return transmute(__float16)u16(s)
|
||||
}
|
||||
m = (m | 0x00800000) >> u32(1 - e)
|
||||
|
||||
@@ -710,14 +767,14 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
m += 0x00002000
|
||||
}
|
||||
|
||||
return u16(s | (m >> 13))
|
||||
return transmute(__float16)u16(s | (m >> 13))
|
||||
} else if e == 0xff - (127 - 15) {
|
||||
if m == 0 {
|
||||
return u16(s | 0x7c00) /* NOTE(bill): infinity */
|
||||
return transmute(__float16)u16(s | 0x7c00) /* NOTE(bill): infinity */
|
||||
} else {
|
||||
/* NOTE(bill): NAN */
|
||||
m >>= 13
|
||||
return u16(s | 0x7c00 | m | i32(m == 0))
|
||||
return transmute(__float16)u16(s | 0x7c00 | m | i32(m == 0))
|
||||
}
|
||||
} else {
|
||||
if m & 0x00001000 != 0 {
|
||||
@@ -737,23 +794,24 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
intrinsics.volatile_store(&f, g)
|
||||
}
|
||||
|
||||
return u16(s | 0x7c00)
|
||||
return transmute(__float16)u16(s | 0x7c00)
|
||||
}
|
||||
|
||||
return u16(s | (e << 10) | (m >> 13))
|
||||
return transmute(__float16)u16(s | (e << 10) | (m >> 13))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
truncdfhf2 :: proc "c" (value: f64) -> u16 {
|
||||
truncdfhf2 :: proc "c" (value: f64) -> __float16 {
|
||||
return truncsfhf2(f32(value))
|
||||
}
|
||||
|
||||
@(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
|
||||
gnu_h2f_ieee :: proc "c" (value_: __float16) -> f32 {
|
||||
fp32 :: struct #raw_union { u: u32, f: f32 }
|
||||
|
||||
value := transmute(u16)value_
|
||||
v: fp32
|
||||
magic, inf_or_nan: fp32
|
||||
magic.u = u32((254 - 15) << 23)
|
||||
@@ -770,12 +828,12 @@ gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
|
||||
|
||||
|
||||
@(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
gnu_f2h_ieee :: proc "c" (value: f32) -> u16 {
|
||||
gnu_f2h_ieee :: proc "c" (value: f32) -> __float16 {
|
||||
return truncsfhf2(value)
|
||||
}
|
||||
|
||||
@(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
extendhfsf2 :: proc "c" (value: u16) -> f32 {
|
||||
extendhfsf2 :: proc "c" (value: __float16) -> f32 {
|
||||
return gnu_h2f_ieee(value)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package runtime
|
||||
|
||||
_OS_Errno :: distinct int
|
||||
|
||||
stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
return _stderr_write(data)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//+build freebsd, openbsd
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="write")
|
||||
_unix_write :: proc(fd: i32, buf: rawptr, size: int) -> int ---
|
||||
|
||||
__error :: proc() -> ^i32 ---
|
||||
}
|
||||
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
ret := _unix_write(2, raw_data(data), len(data))
|
||||
if ret < len(data) {
|
||||
err := __error()
|
||||
return int(ret), _OS_Errno(err^ if err != nil else 0)
|
||||
}
|
||||
return int(ret), 0
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//+build darwin
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
foreign import libc "system:System.framework"
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__stderrp")
|
||||
_stderr: rawptr
|
||||
|
||||
@(link_name="fwrite")
|
||||
_fwrite :: proc(ptr: rawptr, size: uint, nmemb: uint, stream: rawptr) -> uint ---
|
||||
|
||||
@(link_name="__error")
|
||||
_get_errno :: proc() -> ^i32 ---
|
||||
}
|
||||
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
ret := _fwrite(raw_data(data), 1, len(data), _stderr)
|
||||
if ret < len(data) {
|
||||
err := _get_errno()
|
||||
return int(ret), _OS_Errno(err^ if err != nil else 0)
|
||||
}
|
||||
return int(ret), 0
|
||||
}
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
//+build freestanding
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
// TODO(bill): reimplement `os.write`
|
||||
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
return 0, -1
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//+build js
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
foreign import "odin_env"
|
||||
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
foreign odin_env {
|
||||
write :: proc "contextless" (fd: u32, p: []byte) ---
|
||||
}
|
||||
write(1, data)
|
||||
return len(data), 0
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
when ODIN_ARCH == .amd64 {
|
||||
SYS_write :: uintptr(1)
|
||||
} else when ODIN_ARCH == .arm64 {
|
||||
SYS_write :: uintptr(64)
|
||||
} else when ODIN_ARCH == .i386 {
|
||||
SYS_write :: uintptr(4)
|
||||
} else when ODIN_ARCH == .arm32 {
|
||||
SYS_write :: uintptr(4)
|
||||
}
|
||||
|
||||
stderr :: 2
|
||||
|
||||
ret := int(intrinsics.syscall(SYS_write, uintptr(stderr), uintptr(raw_data(data)), uintptr(len(data))))
|
||||
if ret < 0 && ret > -4096 {
|
||||
return 0, _OS_Errno(-ret)
|
||||
}
|
||||
return ret, 0
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
//+build wasi
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
import "core:sys/wasm/wasi"
|
||||
|
||||
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
data := (wasi.ciovec_t)(data)
|
||||
n, err := wasi.fd_write(1, {data})
|
||||
return int(n), _OS_Errno(err)
|
||||
@@ -0,0 +1,51 @@
|
||||
//+build windows
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
foreign import kernel32 "system:Kernel32.lib"
|
||||
|
||||
@(private="file")
|
||||
@(default_calling_convention="system")
|
||||
foreign kernel32 {
|
||||
// NOTE(bill): The types are not using the standard names (e.g. DWORD and LPVOID) to just minimizing the dependency
|
||||
|
||||
// stderr_write
|
||||
GetStdHandle :: proc(which: u32) -> rawptr ---
|
||||
SetHandleInformation :: proc(hObject: rawptr, dwMask: u32, dwFlags: u32) -> b32 ---
|
||||
WriteFile :: proc(hFile: rawptr, lpBuffer: rawptr, nNumberOfBytesToWrite: u32, lpNumberOfBytesWritten: ^u32, lpOverlapped: rawptr) -> b32 ---
|
||||
GetLastError :: proc() -> u32 ---
|
||||
}
|
||||
|
||||
_stderr_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) #no_bounds_check {
|
||||
if len(data) == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
STD_ERROR_HANDLE :: ~u32(0) -12 + 1
|
||||
HANDLE_FLAG_INHERIT :: 0x00000001
|
||||
MAX_RW :: 1<<30
|
||||
|
||||
h := GetStdHandle(STD_ERROR_HANDLE)
|
||||
when size_of(uintptr) == 8 {
|
||||
SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
single_write_length: u32
|
||||
total_write: i64
|
||||
length := i64(len(data))
|
||||
|
||||
for total_write < length {
|
||||
remaining := length - total_write
|
||||
to_write := u32(min(i32(remaining), MAX_RW))
|
||||
|
||||
e := WriteFile(h, &data[total_write], to_write, &single_write_length, nil)
|
||||
if single_write_length <= 0 || !e {
|
||||
err = _OS_Errno(GetLastError())
|
||||
n = int(total_write)
|
||||
return
|
||||
}
|
||||
total_write += i64(single_write_length)
|
||||
}
|
||||
n = int(total_write)
|
||||
return
|
||||
}
|
||||
@@ -2,9 +2,17 @@ package runtime
|
||||
|
||||
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
when !ODIN_DISALLOW_RTTI {
|
||||
print_any_single :: proc(arg: any) {
|
||||
@(private="file")
|
||||
_INTEGER_DIGITS_VAR := _INTEGER_DIGITS
|
||||
|
||||
when !ODIN_NO_RTTI {
|
||||
print_any_single :: proc "contextless" (arg: any) {
|
||||
x := arg
|
||||
if x.data == nil {
|
||||
print_string("nil")
|
||||
return
|
||||
}
|
||||
|
||||
if loc, ok := x.(Source_Code_Location); ok {
|
||||
print_caller_location(loc)
|
||||
return
|
||||
@@ -45,11 +53,18 @@ when !ODIN_DISALLOW_RTTI {
|
||||
case int: print_int(v)
|
||||
case uint: print_uint(v)
|
||||
case uintptr: print_uintptr(v)
|
||||
case rawptr: print_uintptr(uintptr(v))
|
||||
|
||||
case bool: print_string("true" if v else "false")
|
||||
case b8: print_string("true" if v else "false")
|
||||
case b16: print_string("true" if v else "false")
|
||||
case b32: print_string("true" if v else "false")
|
||||
case b64: print_string("true" if v else "false")
|
||||
|
||||
case:
|
||||
ti := type_info_of(x.id)
|
||||
#partial switch v in ti.variant {
|
||||
case Type_Info_Pointer:
|
||||
case Type_Info_Pointer, Type_Info_Multi_Pointer:
|
||||
print_uintptr((^uintptr)(x.data)^)
|
||||
return
|
||||
}
|
||||
@@ -57,8 +72,10 @@ when !ODIN_DISALLOW_RTTI {
|
||||
print_string("<invalid-value>")
|
||||
}
|
||||
}
|
||||
println_any :: proc(args: ..any) {
|
||||
println_any :: proc "contextless" (args: ..any) {
|
||||
context = default_context()
|
||||
loop: for arg, i in args {
|
||||
assert(arg.id != nil)
|
||||
if i != 0 {
|
||||
print_string(" ")
|
||||
}
|
||||
@@ -105,14 +122,14 @@ encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
||||
return buf, 4
|
||||
}
|
||||
|
||||
print_string :: proc "contextless" (str: string) -> (int, _OS_Errno) {
|
||||
return os_write(transmute([]byte)str)
|
||||
print_string :: proc "contextless" (str: string) -> (n: int) {
|
||||
n, _ = stderr_write(transmute([]byte)str)
|
||||
return
|
||||
}
|
||||
|
||||
print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno) {
|
||||
print_strings :: proc "contextless" (args: ..string) -> (n: int) {
|
||||
for str in args {
|
||||
m: int
|
||||
m, err = os_write(transmute([]byte)str)
|
||||
m, err := stderr_write(transmute([]byte)str)
|
||||
n += m
|
||||
if err != 0 {
|
||||
break
|
||||
@@ -121,8 +138,9 @@ print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno)
|
||||
return
|
||||
}
|
||||
|
||||
print_byte :: proc "contextless" (b: byte) -> (int, _OS_Errno) {
|
||||
return os_write([]byte{b})
|
||||
print_byte :: proc "contextless" (b: byte) -> (n: int) {
|
||||
n, _ = stderr_write([]byte{b})
|
||||
return
|
||||
}
|
||||
|
||||
print_encoded_rune :: proc "contextless" (r: rune) {
|
||||
@@ -141,11 +159,10 @@ print_encoded_rune :: proc "contextless" (r: rune) {
|
||||
if r <= 0 {
|
||||
print_string("\\x00")
|
||||
} else if r < 32 {
|
||||
digits := _INTEGER_DIGITS
|
||||
n0, n1 := u8(r) >> 4, u8(r) & 0xf
|
||||
print_string("\\x")
|
||||
print_byte(digits[n0])
|
||||
print_byte(digits[n1])
|
||||
print_byte(_INTEGER_DIGITS_VAR[n0])
|
||||
print_byte(_INTEGER_DIGITS_VAR[n1])
|
||||
} else {
|
||||
print_rune(r)
|
||||
}
|
||||
@@ -153,7 +170,7 @@ print_encoded_rune :: proc "contextless" (r: rune) {
|
||||
print_byte('\'')
|
||||
}
|
||||
|
||||
print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check {
|
||||
print_rune :: proc "contextless" (r: rune) -> int #no_bounds_check {
|
||||
RUNE_SELF :: 0x80
|
||||
|
||||
if r < RUNE_SELF {
|
||||
@@ -161,29 +178,27 @@ print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check
|
||||
}
|
||||
|
||||
b, n := encode_rune(r)
|
||||
return os_write(b[:n])
|
||||
m, _ := stderr_write(b[:n])
|
||||
return m
|
||||
}
|
||||
|
||||
|
||||
print_u64 :: proc "contextless" (x: u64) #no_bounds_check {
|
||||
digits := _INTEGER_DIGITS
|
||||
|
||||
a: [129]byte
|
||||
i := len(a)
|
||||
b := u64(10)
|
||||
u := x
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
u /= b
|
||||
}
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
|
||||
os_write(a[i:])
|
||||
stderr_write(a[i:])
|
||||
}
|
||||
|
||||
|
||||
print_i64 :: proc "contextless" (x: i64) #no_bounds_check {
|
||||
digits := _INTEGER_DIGITS
|
||||
b :: i64(10)
|
||||
|
||||
u := x
|
||||
@@ -193,41 +208,41 @@ print_i64 :: proc "contextless" (x: i64) #no_bounds_check {
|
||||
a: [129]byte
|
||||
i := len(a)
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
u /= b
|
||||
}
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
|
||||
if neg {
|
||||
i -= 1; a[i] = '-'
|
||||
}
|
||||
|
||||
os_write(a[i:])
|
||||
stderr_write(a[i:])
|
||||
}
|
||||
|
||||
print_uint :: proc "contextless" (x: uint) { print_u64(u64(x)) }
|
||||
print_uintptr :: proc "contextless" (x: uintptr) { print_u64(u64(x)) }
|
||||
print_int :: proc "contextless" (x: int) { print_i64(i64(x)) }
|
||||
|
||||
print_caller_location :: proc "contextless" (using loc: Source_Code_Location) {
|
||||
print_string(file_path)
|
||||
print_caller_location :: proc "contextless" (loc: Source_Code_Location) {
|
||||
print_string(loc.file_path)
|
||||
when ODIN_ERROR_POS_STYLE == .Default {
|
||||
print_byte('(')
|
||||
print_u64(u64(line))
|
||||
print_u64(u64(loc.line))
|
||||
print_byte(':')
|
||||
print_u64(u64(column))
|
||||
print_u64(u64(loc.column))
|
||||
print_byte(')')
|
||||
} else when ODIN_ERROR_POS_STYLE == .Unix {
|
||||
print_byte(':')
|
||||
print_u64(u64(line))
|
||||
print_u64(u64(loc.line))
|
||||
print_byte(':')
|
||||
print_u64(u64(column))
|
||||
print_u64(u64(loc.column))
|
||||
print_byte(':')
|
||||
} else {
|
||||
#panic("unhandled ODIN_ERROR_POS_STYLE")
|
||||
}
|
||||
}
|
||||
print_typeid :: proc "contextless" (id: typeid) {
|
||||
when ODIN_DISALLOW_RTTI {
|
||||
when ODIN_NO_RTTI {
|
||||
if id == nil {
|
||||
print_string("nil")
|
||||
} else {
|
||||
@@ -303,7 +318,7 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
if info.params == nil {
|
||||
print_string("()")
|
||||
} else {
|
||||
t := info.params.variant.(Type_Info_Tuple)
|
||||
t := info.params.variant.(Type_Info_Parameters)
|
||||
print_byte('(')
|
||||
for t, i in t.types {
|
||||
if i > 0 { print_string(", ") }
|
||||
@@ -315,7 +330,7 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
print_string(" -> ")
|
||||
print_type(info.results)
|
||||
}
|
||||
case Type_Info_Tuple:
|
||||
case Type_Info_Parameters:
|
||||
count := len(info.names)
|
||||
if count != 1 { print_byte('(') }
|
||||
for name, i in info.names {
|
||||
@@ -383,9 +398,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
if info.is_packed { print_string("#packed ") }
|
||||
if info.is_raw_union { print_string("#raw_union ") }
|
||||
if info.custom_align {
|
||||
print_string("#align ")
|
||||
print_string("#align(")
|
||||
print_u64(u64(ti.align))
|
||||
print_byte(' ')
|
||||
print_string(") ")
|
||||
}
|
||||
print_byte('{')
|
||||
for name, i in info.names {
|
||||
@@ -399,8 +414,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
case Type_Info_Union:
|
||||
print_string("union ")
|
||||
if info.custom_align {
|
||||
print_string("#align ")
|
||||
print_string("#align(")
|
||||
print_u64(u64(ti.align))
|
||||
print_string(") ")
|
||||
}
|
||||
if info.no_nil {
|
||||
print_string("#no_nil ")
|
||||
@@ -456,11 +472,11 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
print_string(") ")
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Relative_Slice:
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
print_string("#relative(")
|
||||
print_type(info.base_integer)
|
||||
print_string(") ")
|
||||
print_type(info.slice)
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Matrix:
|
||||
print_string("matrix[")
|
||||
@@ -4,7 +4,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
foreign import lib "system:NtDll.lib"
|
||||
|
||||
@(private="file")
|
||||
@(default_calling_convention="stdcall")
|
||||
@(default_calling_convention="system")
|
||||
foreign lib {
|
||||
RtlMoveMemory :: proc(dst, s: rawptr, length: int) ---
|
||||
RtlFillMemory :: proc(dst: rawptr, length: int, fill: i32) ---
|
||||
@@ -25,19 +25,30 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
RtlMoveMemory(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64) {
|
||||
} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32) {
|
||||
@(link_name="memset", linkage="strong", require)
|
||||
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
|
||||
if ptr != nil && len != 0 {
|
||||
b := byte(val)
|
||||
p := ([^]byte)(ptr)
|
||||
for i in 0..<len {
|
||||
for i := 0; i < len; i += 1 {
|
||||
p[i] = b
|
||||
}
|
||||
}
|
||||
return ptr
|
||||
}
|
||||
|
||||
|
||||
@(link_name="bzero", linkage="strong", require)
|
||||
bzero :: proc "c" (ptr: rawptr, len: int) -> rawptr {
|
||||
if ptr != nil && len != 0 {
|
||||
p := ([^]byte)(ptr)
|
||||
for i := 0; i < len; i += 1 {
|
||||
p[i] = 0
|
||||
}
|
||||
}
|
||||
return ptr
|
||||
}
|
||||
|
||||
@(link_name="memmove", linkage="strong", require)
|
||||
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
d, s := ([^]byte)(dst), ([^]byte)(src)
|
||||
@@ -75,7 +86,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
if ptr != nil && len != 0 {
|
||||
b := byte(val)
|
||||
p := ([^]byte)(ptr)
|
||||
for i in 0..<len {
|
||||
for i := 0; i < len; i += 1 {
|
||||
p[i] = b
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package runtime
|
||||
|
||||
foreign import "system:Foundation.framework"
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
objc_id :: ^intrinsics.objc_object
|
||||
objc_Class :: ^intrinsics.objc_class
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build js wasm32
|
||||
//+build js
|
||||
package runtime
|
||||
|
||||
init_default_context_for_js: Context
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build wasm32
|
||||
//+build wasm32, wasm64p32
|
||||
package runtime
|
||||
|
||||
@(private="file")
|
||||
@@ -8,7 +8,7 @@ ti_int :: struct #raw_union {
|
||||
}
|
||||
|
||||
@(link_name="__ashlti3", linkage="strong")
|
||||
__ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 {
|
||||
__ashlti3 :: proc "contextless" (a: i128, b_: u32) -> i128 {
|
||||
bits_in_dword :: size_of(u32)*8
|
||||
b := u32(b_)
|
||||
|
||||
@@ -29,7 +29,7 @@ __ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 {
|
||||
|
||||
|
||||
@(link_name="__multi3", linkage="strong")
|
||||
__multi3 :: proc "c" (a, b: i128) -> i128 {
|
||||
__multi3 :: proc "contextless" (a, b: i128) -> i128 {
|
||||
x, y, r: ti_int
|
||||
|
||||
x.all = a
|
||||
@@ -0,0 +1,79 @@
|
||||
bits 64
|
||||
|
||||
global __chkstk
|
||||
global _tls_index
|
||||
global _fltused
|
||||
|
||||
section .data
|
||||
_tls_index: dd 0
|
||||
_fltused: dd 0x9875
|
||||
|
||||
section .text
|
||||
; NOTE(flysand): The function call to __chkstk is called
|
||||
; by the compiler, when we're allocating arrays larger than
|
||||
; a page size. The reason is because the OS doesn't map the
|
||||
; whole stack into memory all at once, but does so page-by-page.
|
||||
; When the next page is touched, the CPU generates a page fault,
|
||||
; which *the OS* is handling by allocating the next page in the
|
||||
; stack until we reach the limit of stack size.
|
||||
;
|
||||
; This page is called the guard page, touching it will extend
|
||||
; the size of the stack and overwrite the stack limit in the TEB.
|
||||
;
|
||||
; If we allocate a large enough array and start writing from the
|
||||
; bottom of it, it's possible that we may start touching
|
||||
; non-contiguous pages which are unmapped. OS only maps the stack
|
||||
; page into the memory if the page above it was also mapped.
|
||||
;
|
||||
; Therefore the compilers insert this routine, the sole purpose
|
||||
; of which is to step through the stack starting from the RSP
|
||||
; down to the new RSP after allocation, and touch every page
|
||||
; of the new allocation so that the stack is fully mapped for
|
||||
; the new allocation
|
||||
;
|
||||
; I've gotten this code by disassembling the output of MSVC long
|
||||
; time ago. I don't remember if I've cleaned it up, but it definately
|
||||
; stinks.
|
||||
;
|
||||
; Additional notes:
|
||||
; RAX (passed as parameter) holds the allocation's size
|
||||
; GS:[0x10] references the current stack limit
|
||||
; (i.e. bottom of the stack (i.e. lowest address accessible))
|
||||
;
|
||||
; Also this stuff is windows-only kind of thing, because linux people
|
||||
; didn't think stack that grows is cool enough for them, but the kernel
|
||||
; totally supports this kind of stack.
|
||||
__chkstk:
|
||||
;; Allocate 16 bytes to store values of r10 and r11
|
||||
sub rsp, 0x10
|
||||
mov [rsp], r10
|
||||
mov [rsp+0x8], r11
|
||||
;; Set r10 to point to the stack as of the moment of the function call
|
||||
lea r10, [rsp+0x18]
|
||||
;; Subtract r10 til the bottom of the stack allocation, if we overflow
|
||||
;; reset r10 to 0, we'll crash with segfault anyway
|
||||
xor r11, r11
|
||||
sub r10, rax
|
||||
cmovb r10, r11
|
||||
;; Load r11 with the bottom of the stack (lowest allocated address)
|
||||
mov r11, gs:[0x10] ; NOTE(flysand): gs:[0x10] is stack limit
|
||||
;; If the bottom of the allocation is above the bottom of the stack,
|
||||
;; we don't need to probe
|
||||
cmp r10, r11
|
||||
jnb .end
|
||||
;; Align the bottom of the allocation down to page size
|
||||
and r10w, 0xf000
|
||||
.loop:
|
||||
;; Move the pointer to the next guard page, and touch it by loading 0
|
||||
;; into that page
|
||||
lea r11, [r11-0x1000]
|
||||
mov byte [r11], 0x0
|
||||
;; Did we reach the bottom of the allocation?
|
||||
cmp r10, r11
|
||||
jnz .loop
|
||||
.end:
|
||||
;; Restore previous r10 and r11 and return
|
||||
mov r10, [rsp]
|
||||
mov r11, [rsp+0x8]
|
||||
add rsp, 0x10
|
||||
ret
|
||||
@@ -1,11 +1,12 @@
|
||||
//+private
|
||||
//+no-instrumentation
|
||||
package runtime
|
||||
|
||||
foreign import kernel32 "system:Kernel32.lib"
|
||||
|
||||
@(private)
|
||||
foreign kernel32 {
|
||||
RaiseException :: proc "stdcall" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: u32, lpArguments: ^uint) -> ! ---
|
||||
RaiseException :: proc "system" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: u32, lpArguments: ^uint) -> ! ---
|
||||
}
|
||||
|
||||
windows_trap_array_bounds :: proc "contextless" () -> ! {
|
||||
@@ -1,4 +1,5 @@
|
||||
//+private
|
||||
//+no-instrumentation
|
||||
package runtime
|
||||
|
||||
@require foreign import "system:int64.lib"
|
||||
@@ -12,7 +13,7 @@ windows_trap_array_bounds :: proc "contextless" () -> ! {
|
||||
EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C
|
||||
|
||||
foreign kernel32 {
|
||||
RaiseException :: proc "stdcall" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
|
||||
RaiseException :: proc "system" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
|
||||
}
|
||||
|
||||
RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, nil)
|
||||
@@ -1,6 +1,6 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
|
||||
_ctz :: intrinsics.count_trailing_zeros
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,18 +3,20 @@
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
where /Q cl.exe || (
|
||||
set __VSCMD_ARG_NO_LOGO=1
|
||||
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
|
||||
if "!VS!" equ "" (
|
||||
echo ERROR: Visual Studio installation not found
|
||||
exit /b 1
|
||||
)
|
||||
call "!VS!\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /b 1
|
||||
set __VSCMD_ARG_NO_LOGO=1
|
||||
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
|
||||
if "!VS!" equ "" (
|
||||
echo ERROR: Visual Studio installation not found
|
||||
exit /b 1
|
||||
)
|
||||
call "!VS!\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /b 1
|
||||
)
|
||||
|
||||
if "%VSCMD_ARG_TGT_ARCH%" neq "x64" (
|
||||
echo ERROR: please run this from MSVC x64 native tools command prompt, 32-bit target is not supported!
|
||||
exit /b 1
|
||||
if "%ODIN_IGNORE_MSVC_CHECK%" == "" (
|
||||
echo ERROR: please run this from MSVC x64 native tools command prompt, 32-bit target is not supported!
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (
|
||||
@@ -48,8 +50,14 @@ set odin_version_raw="dev-%curr_year%-%curr_month%"
|
||||
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
|
||||
set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\"
|
||||
|
||||
for /f %%i in ('git rev-parse --short HEAD') do set GIT_SHA=%%i
|
||||
if not exist .git\ goto skip_git_hash
|
||||
for /f "tokens=1,2" %%i IN ('git show "--pretty=%%cd %%h" "--date=format:%%Y-%%m" --no-patch --no-notes HEAD') do (
|
||||
set odin_version_raw=dev-%%i
|
||||
set GIT_SHA=%%j
|
||||
)
|
||||
if %ERRORLEVEL% equ 0 set compiler_defines=%compiler_defines% -DGIT_SHA=\"%GIT_SHA%\"
|
||||
:skip_git_hash
|
||||
|
||||
if %nightly% equ 1 set compiler_defines=%compiler_defines% -DNIGHTLY
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
@@ -72,6 +80,16 @@ set libs= ^
|
||||
Synchronization.lib ^
|
||||
bin\llvm\windows\LLVM-C.lib
|
||||
|
||||
rem DO NOT TOUCH!
|
||||
rem THIS TILDE STUFF IS FOR DEVELOPMENT ONLY!
|
||||
set tilde_backend=0
|
||||
if %tilde_backend% EQU 1 (
|
||||
set libs=%libs% src\tilde\tb.lib
|
||||
set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND
|
||||
)
|
||||
rem DO NOT TOUCH!
|
||||
|
||||
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
@@ -92,8 +110,9 @@ if %errorlevel% neq 0 goto end_of_build
|
||||
call build_vendor.bat
|
||||
if %errorlevel% neq 0 goto end_of_build
|
||||
|
||||
if %release_mode% EQU 0 odin run examples/demo
|
||||
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
|
||||
if %release_mode% EQU 0 odin run examples/demo -- Hellope World
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
:end_of_build
|
||||
:end_of_build
|
||||
+79
-137
@@ -1,123 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
: ${CXX=clang++}
|
||||
: ${CPPFLAGS=}
|
||||
: ${CXX=clang++}
|
||||
: ${CXXFLAGS=}
|
||||
: ${LDFLAGS=}
|
||||
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
|
||||
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
|
||||
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)
|
||||
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
||||
OS_ARCH="$(uname -m)"
|
||||
OS_NAME="$(uname -s)"
|
||||
|
||||
panic() {
|
||||
printf "%s\n" "$1"
|
||||
if [ -d ".git" ] && [ -n "$(command -v git)" ]; then
|
||||
GIT_SHA=$(git show --pretty='%h' --no-patch --no-notes HEAD)
|
||||
CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""
|
||||
fi
|
||||
|
||||
error() {
|
||||
printf "ERROR: %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")
|
||||
if [ -z "$LLVM_CONFIG" ]; then
|
||||
# darwin, linux, openbsd
|
||||
if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17"
|
||||
elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14"
|
||||
elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13"
|
||||
elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12"
|
||||
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
|
||||
# freebsd
|
||||
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17"
|
||||
elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config-14"
|
||||
elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13"
|
||||
elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12"
|
||||
elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11"
|
||||
# fallback
|
||||
elif [ -n "$(command -v llvm-config)" ]; then LLVM_CONFIG="llvm-config"
|
||||
else
|
||||
# allow for x86 / amd64 all llvm versions beginning from 11
|
||||
MIN_LLVM_VERSION=("11.1.0")
|
||||
error "No llvm-config command found. Set LLVM_CONFIG to proceed."
|
||||
fi
|
||||
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"
|
||||
LLVM_VERSION="$($LLVM_CONFIG --version)"
|
||||
LLVM_VERSION_MAJOR="$(echo $LLVM_VERSION | awk -F. '{print $1}')"
|
||||
LLVM_VERSION_MINOR="$(echo $LLVM_VERSION | awk -F. '{print $2}')"
|
||||
LLVM_VERSION_PATCH="$(echo $LLVM_VERSION | awk -F. '{print $3}')"
|
||||
|
||||
if [ $LLVM_VERSION_MAJOR -lt 11 ] ||
|
||||
([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]); then
|
||||
error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14 or 17"
|
||||
fi
|
||||
|
||||
case "$OS_NAME" in
|
||||
Darwin)
|
||||
if [ "$OS_ARCH" == "arm64" ]; then
|
||||
if [ $LLVM_VERSION_MAJOR -lt 13 ] || [ $LLVM_VERSION_MAJOR -gt 17 ]; then
|
||||
error "Darwin Arm64 requires LLVM 13, 14 or 17"
|
||||
fi
|
||||
fi
|
||||
|
||||
MAX_LLVM_VERSION=("14.999.999")
|
||||
if [ $(version $($LLVM_CONFIG --version)) -gt $(version $MAX_LLVM_VERSION) ]; then
|
||||
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
|
||||
panic "Requirement: llvm-config must be base version smaller than 15"
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl -framework System"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||
}
|
||||
|
||||
config_freebsd() {
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
if [ ! "$LLVM_CONFIG" ]; then
|
||||
if which llvm-config11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config11
|
||||
elif which llvm-config12 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config12
|
||||
elif which llvm-config13 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config13
|
||||
else
|
||||
panic "Unable to find LLVM-config"
|
||||
fi
|
||||
fi
|
||||
|
||||
;;
|
||||
FreeBSD)
|
||||
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"
|
||||
;;
|
||||
Linux)
|
||||
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
|
||||
|
||||
MAX_LLVM_VERSION=("14.999.999")
|
||||
if [ $(version $($LLVM_CONFIG --version)) -gt $(version $MAX_LLVM_VERSION) ]; then
|
||||
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
|
||||
panic "Requirement: llvm-config must be base version smaller than 15"
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs --libfiles) -Wl,-rpath=\$ORIGIN"
|
||||
|
||||
# Creates a copy of the llvm library in the build dir, this is meant to support compiler explorer.
|
||||
# The annoyance is that this copy can be cluttering the development folder. TODO: split staging folders
|
||||
# for development and compiler explorer builds
|
||||
LDFLAGS="$LDFLAGS -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)"
|
||||
# Copy libLLVM*.so into current directory for linking
|
||||
# NOTE: This is needed by the Linux release pipeline!
|
||||
cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./
|
||||
}
|
||||
LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
|
||||
;;
|
||||
OpenBSD)
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -liconv"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
;;
|
||||
*)
|
||||
error "Platform \"$OS_NAME\" unsupported"
|
||||
;;
|
||||
esac
|
||||
|
||||
build_odin() {
|
||||
case $1 in
|
||||
@@ -128,13 +97,20 @@ build_odin() {
|
||||
EXTRAFLAGS="-O3"
|
||||
;;
|
||||
release-native)
|
||||
EXTRAFLAGS="-O3 -march=native"
|
||||
if [ "$OS_ARCH" == "arm64" ]; then
|
||||
# Use preferred flag for Arm (ie arm64 / aarch64 / etc)
|
||||
EXTRAFLAGS="-O3 -mcpu=native"
|
||||
else
|
||||
# Use preferred flag for x86 / amd64
|
||||
EXTRAFLAGS="-O3 -march=native"
|
||||
fi
|
||||
;;
|
||||
nightly)
|
||||
EXTRAFLAGS="-DNIGHTLY -O3"
|
||||
;;
|
||||
*)
|
||||
panic "Build mode unsupported!"
|
||||
error "Build mode \"$1\" unsupported!"
|
||||
;;
|
||||
esac
|
||||
|
||||
set -x
|
||||
@@ -143,57 +119,23 @@ build_odin() {
|
||||
}
|
||||
|
||||
run_demo() {
|
||||
./odin run examples/demo/demo.odin -file
|
||||
./odin run examples/demo/demo.odin -file -- Hellope World
|
||||
}
|
||||
|
||||
have_which() {
|
||||
if ! which which > /dev/null 2>&1; then
|
||||
panic "Could not find \`which\`"
|
||||
fi
|
||||
}
|
||||
|
||||
have_which
|
||||
|
||||
case $OS in
|
||||
Linux)
|
||||
config_linux
|
||||
;;
|
||||
Darwin)
|
||||
config_darwin
|
||||
;;
|
||||
OpenBSD)
|
||||
config_openbsd
|
||||
;;
|
||||
FreeBSD)
|
||||
config_freebsd
|
||||
;;
|
||||
*)
|
||||
panic "Platform unsupported!"
|
||||
esac
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
if [ $# -eq 0 ]; then
|
||||
build_odin debug
|
||||
run_demo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
elif [ $# -eq 1 ]; then
|
||||
case $1 in
|
||||
report)
|
||||
if [[ ! -f "./odin" ]]; then
|
||||
build_odin debug
|
||||
fi
|
||||
|
||||
[ ! -f "./odin" ] && build_odin debug
|
||||
./odin report
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
build_odin $1
|
||||
;;
|
||||
esac
|
||||
|
||||
run_demo
|
||||
exit 0
|
||||
else
|
||||
panic "Too many arguments!"
|
||||
error "Too many arguments!"
|
||||
fi
|
||||
|
||||
@@ -2,25 +2,25 @@ package bufio
|
||||
|
||||
import "core:io"
|
||||
|
||||
// Loadahead_Reader provides io lookahead.
|
||||
// Lookahead_Reader provides io lookahead.
|
||||
// This is useful for tokenizers/parsers.
|
||||
// Loadahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Loadahead_Reader's buffer size
|
||||
// Lookahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Lookahead_Reader's buffer size
|
||||
// will EXACTLY match the specified size, whereas bufio.Reader's buffer size may differ from the specified size.
|
||||
// This makes sure that the buffer will not be accidentally read beyond the expected size.
|
||||
Loadahead_Reader :: struct {
|
||||
Lookahead_Reader :: struct {
|
||||
r: io.Reader,
|
||||
buf: []byte,
|
||||
n: int,
|
||||
}
|
||||
|
||||
lookahead_reader_init :: proc(lr: ^Loadahead_Reader, r: io.Reader, buf: []byte) -> ^Loadahead_Reader {
|
||||
lookahead_reader_init :: proc(lr: ^Lookahead_Reader, r: io.Reader, buf: []byte) -> ^Lookahead_Reader {
|
||||
lr.r = r
|
||||
lr.buf = buf
|
||||
lr.n = 0
|
||||
return lr
|
||||
}
|
||||
|
||||
lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
|
||||
lookahead_reader_buffer :: proc(lr: ^Lookahead_Reader) -> []byte {
|
||||
return lr.buf[:lr.n]
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
|
||||
// lookahead_reader_peek returns a slice of the Lookahead_Reader which holds n bytes
|
||||
// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
|
||||
// NOTE: The returned buffer is not a copy of the underlying buffer
|
||||
lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Error) {
|
||||
lookahead_reader_peek :: proc(lr: ^Lookahead_Reader, n: int) -> ([]byte, io.Error) {
|
||||
switch {
|
||||
case n < 0:
|
||||
return nil, .Negative_Read
|
||||
@@ -58,13 +58,13 @@ lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Erro
|
||||
// lookahead_reader_peek_all returns a slice of the Lookahead_Reader populating the full buffer
|
||||
// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
|
||||
// NOTE: The returned buffer is not a copy of the underlying buffer
|
||||
lookahead_reader_peek_all :: proc(lr: ^Loadahead_Reader) -> ([]byte, io.Error) {
|
||||
lookahead_reader_peek_all :: proc(lr: ^Lookahead_Reader) -> ([]byte, io.Error) {
|
||||
return lookahead_reader_peek(lr, len(lr.buf))
|
||||
}
|
||||
|
||||
|
||||
// lookahead_reader_consume drops the first n populated bytes from the Lookahead_Reader.
|
||||
lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
|
||||
lookahead_reader_consume :: proc(lr: ^Lookahead_Reader, n: int) -> io.Error {
|
||||
switch {
|
||||
case n == 0:
|
||||
return nil
|
||||
@@ -78,6 +78,6 @@ lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
lookahead_reader_consume_all :: proc(lr: ^Loadahead_Reader) -> io.Error {
|
||||
lookahead_reader_consume_all :: proc(lr: ^Lookahead_Reader) -> io.Error {
|
||||
return lookahead_reader_consume(lr, lr.n)
|
||||
}
|
||||
|
||||
+22
-44
@@ -14,51 +14,29 @@ read_writer_init :: proc(rw: ^Read_Writer, r: ^Reader, w: ^Writer) {
|
||||
}
|
||||
|
||||
read_writer_to_stream :: proc(rw: ^Read_Writer) -> (s: io.Stream) {
|
||||
s.stream_data = rw
|
||||
s.stream_vtable = &_read_writer_vtable
|
||||
s.procedure = _read_writer_procedure
|
||||
s.data = rw
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_read_writer_vtable := io.Stream_VTable{
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read(b, p)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_unread_byte(b)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read_rune(b)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_unread_rune(b)
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_write_to(b, w)
|
||||
},
|
||||
impl_flush = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_flush(b)
|
||||
},
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_write(b, p)
|
||||
},
|
||||
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_write_byte(b, c)
|
||||
},
|
||||
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_write_rune(b, r)
|
||||
},
|
||||
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).w
|
||||
return writer_read_from(b, r)
|
||||
},
|
||||
}
|
||||
_read_writer_procedure := proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
rw := (^Read_Writer)(stream_data)
|
||||
n_int: int
|
||||
#partial switch mode {
|
||||
case .Flush:
|
||||
err = writer_flush(rw.w)
|
||||
return
|
||||
case .Read:
|
||||
n_int, err = reader_read(rw.r, p)
|
||||
n = i64(n_int)
|
||||
return
|
||||
case .Write:
|
||||
n_int, err = writer_write(rw.w, p)
|
||||
n = i64(n_int)
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Flush, .Read, .Write, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
+26
-76
@@ -118,9 +118,7 @@ reader_peek :: proc(b: ^Reader, n: int) -> (data: []byte, err: io.Error) {
|
||||
b.last_rune_size = -1
|
||||
|
||||
for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
|
||||
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
|
||||
return nil, fill_err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
if n > len(b.buf) {
|
||||
@@ -156,9 +154,7 @@ reader_discard :: proc(b: ^Reader, n: int) -> (discarded: int, err: io.Error) {
|
||||
for {
|
||||
skip := reader_buffered(b)
|
||||
if skip == 0 {
|
||||
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
|
||||
return 0, fill_err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
skip = reader_buffered(b)
|
||||
}
|
||||
skip = min(skip, remaining)
|
||||
@@ -223,20 +219,18 @@ reader_read :: proc(b: ^Reader, p: []byte) -> (n: int, err: io.Error) {
|
||||
|
||||
// reader_read_byte reads and returns a single byte
|
||||
// If no byte is available, it return an error
|
||||
reader_read_byte :: proc(b: ^Reader) -> (byte, io.Error) {
|
||||
reader_read_byte :: proc(b: ^Reader) -> (c: byte, err: io.Error) {
|
||||
b.last_rune_size = -1
|
||||
for b.r == b.w {
|
||||
if b.err != nil {
|
||||
return 0, _reader_consume_err(b)
|
||||
}
|
||||
if err := _reader_read_new_chunk(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
c := b.buf[b.r]
|
||||
c = b.buf[b.r]
|
||||
b.r += 1
|
||||
b.last_byte = int(c)
|
||||
return c, nil
|
||||
return
|
||||
}
|
||||
|
||||
// reader_unread_byte unreads the last byte. Only the most recently read byte can be unread
|
||||
@@ -264,15 +258,12 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
|
||||
!utf8.full_rune(b.buf[b.r:b.w]) &&
|
||||
b.err == nil &&
|
||||
b.w-b.w < len(b.buf) {
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
b.last_rune_size = -1
|
||||
if b.r == b.w {
|
||||
err = _reader_consume_err(b)
|
||||
return
|
||||
return 0, 0, _reader_consume_err(b)
|
||||
}
|
||||
r, size = rune(b.buf[b.r]), 1
|
||||
if r >= utf8.RUNE_SELF {
|
||||
@@ -305,39 +296,20 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
return i64(n), err
|
||||
}
|
||||
|
||||
n, err = write_buf(b, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n = write_buf(b, w) or_return
|
||||
|
||||
m: i64
|
||||
if nr, ok := io.to_writer_to(b.rd); ok {
|
||||
m, err = io.write_to(nr, w)
|
||||
n += m
|
||||
return n, err
|
||||
}
|
||||
|
||||
if nw, ok := io.to_reader_from(w); ok {
|
||||
m, err = io.read_from(nw, b.rd)
|
||||
n += m
|
||||
return n, err
|
||||
}
|
||||
|
||||
if b.w-b.r < len(b.buf) {
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
for b.r < b.w {
|
||||
m, err = write_buf(b, w)
|
||||
n += m
|
||||
n += m // this needs to be done before returning
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
if b.err == .EOF {
|
||||
@@ -352,48 +324,28 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
|
||||
// reader_to_stream converts a Reader into an io.Stream
|
||||
reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = &_reader_vtable
|
||||
s.data = b
|
||||
s.procedure = _reader_proc
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_reader_vtable := io.Stream_VTable{
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
b := (^Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
return io._i64_err(reader_read(b, p))
|
||||
case .Destroy:
|
||||
reader_destroy(b)
|
||||
return nil
|
||||
},
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_read(b, p)
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_read_byte(b)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_unread_byte(b)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_read_rune(b)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_unread_rune(b)
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
b := (^Reader)(s.stream_data)
|
||||
return reader_write_to(b, w)
|
||||
},
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Destroy, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Utility procedures
|
||||
//
|
||||
@@ -435,9 +387,7 @@ reader_read_slice :: proc(b: ^Reader, delim: byte) -> (line: []byte, err: io.Err
|
||||
|
||||
s = b.w - b.r
|
||||
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
break
|
||||
}
|
||||
_reader_read_new_chunk(b) or_break
|
||||
}
|
||||
|
||||
if i := len(line)-1; i >= 0 {
|
||||
|
||||
@@ -4,7 +4,7 @@ import "core:bytes"
|
||||
import "core:io"
|
||||
import "core:mem"
|
||||
import "core:unicode/utf8"
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
// Extra errors returns by scanning procedures
|
||||
Scanner_Extra_Error :: enum i32 {
|
||||
|
||||
+25
-36
@@ -159,7 +159,7 @@ writer_write_rune :: proc(b: ^Writer, r: rune) -> (size: int, err: io.Error) {
|
||||
return
|
||||
}
|
||||
|
||||
// writer_write writes a string into the buffer
|
||||
// writer_write_string writes a string into the buffer
|
||||
// It returns the number of bytes written
|
||||
// If n < len(p), it will return an error explaining why the write is short
|
||||
writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) {
|
||||
@@ -173,14 +173,6 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
if b.err != nil {
|
||||
return 0, b.err
|
||||
}
|
||||
if writer_buffered(b) == 0 {
|
||||
if w, ok := io.to_reader_from(b.wr); !ok {
|
||||
n, err = io.read_from(w, r)
|
||||
b.err = err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
if writer_available(b) == 0 {
|
||||
writer_flush(b) or_return
|
||||
@@ -222,38 +214,35 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
|
||||
// writer_to_stream converts a Writer into an io.Stream
|
||||
writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = &_writer_vtable
|
||||
s.data = b
|
||||
s.procedure = _writer_proc
|
||||
return
|
||||
}
|
||||
|
||||
// writer_to_stream converts a Writer into an io.Stream
|
||||
writer_to_writer :: proc(b: ^Writer) -> (s: io.Writer) {
|
||||
return writer_to_stream(b)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_writer_vtable := io.Stream_VTable{
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
_writer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
b := (^Writer)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Flush:
|
||||
err = writer_flush(b)
|
||||
return
|
||||
case .Write:
|
||||
n_int: int
|
||||
n_int, err = writer_write(b, p)
|
||||
n = i64(n_int)
|
||||
return
|
||||
case .Destroy:
|
||||
writer_destroy(b)
|
||||
return nil
|
||||
},
|
||||
impl_flush = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_flush(b)
|
||||
},
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_write(b, p)
|
||||
},
|
||||
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_write_byte(b, c)
|
||||
},
|
||||
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_write_rune(b, r)
|
||||
},
|
||||
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
b := (^Writer)(s.stream_data)
|
||||
return writer_read_from(b, r)
|
||||
},
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Flush, .Write, .Destroy, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
+31
-61
@@ -38,6 +38,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) {
|
||||
}
|
||||
|
||||
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
|
||||
if b.buf == nil {
|
||||
b.buf = make([dynamic]byte, len, cap, allocator)
|
||||
return
|
||||
}
|
||||
|
||||
b.buf.allocator = allocator
|
||||
reserve(&b.buf, cap)
|
||||
resize(&b.buf, len)
|
||||
@@ -108,8 +113,11 @@ _buffer_grow :: proc(b: ^Buffer, n: int) -> int {
|
||||
if i, ok := _buffer_try_grow(b, n); ok {
|
||||
return i
|
||||
}
|
||||
|
||||
if b.buf == nil && n <= SMALL_BUFFER_SIZE {
|
||||
b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE)
|
||||
// Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator
|
||||
reserve(&b.buf, SMALL_BUFFER_SIZE)
|
||||
resize(&b.buf, n)
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -370,69 +378,31 @@ buffer_read_from :: proc(b: ^Buffer, r: io.Reader) -> (n: i64, err: io.Error) #n
|
||||
|
||||
|
||||
buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = &_buffer_vtable
|
||||
s.data = b
|
||||
s.procedure = _buffer_proc
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_buffer_vtable := io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return i64(buffer_capacity(b))
|
||||
},
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read(b, p)
|
||||
},
|
||||
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_at(b, p, int(offset))
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_byte(b)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_rune(b)
|
||||
},
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write(b, p)
|
||||
},
|
||||
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_at(b, p, int(offset))
|
||||
},
|
||||
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_byte(b, c)
|
||||
},
|
||||
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_rune(b, r)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_unread_byte(b)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_unread_rune(b)
|
||||
},
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
_buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
b := (^Buffer)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
return io._i64_err(buffer_read(b, p))
|
||||
case .Read_At:
|
||||
return io._i64_err(buffer_read_at(b, p, int(offset)))
|
||||
case .Write:
|
||||
return io._i64_err(buffer_write(b, p))
|
||||
case .Write_At:
|
||||
return io._i64_err(buffer_write_at(b, p, int(offset)))
|
||||
case .Size:
|
||||
n = i64(buffer_capacity(b))
|
||||
return
|
||||
case .Destroy:
|
||||
buffer_destroy(b)
|
||||
return nil
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_write_to(b, w)
|
||||
},
|
||||
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return buffer_read_from(b, r)
|
||||
},
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Size, .Destroy})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
@@ -895,7 +895,7 @@ split_multi_iterator :: proc(s: ^[]byte, substrs: [][]byte, skip_empty := false)
|
||||
|
||||
|
||||
|
||||
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
|
||||
// Scrubs invalid utf-8 characters and replaces them with the replacement string
|
||||
// Adjacent invalid bytes are only replaced once
|
||||
scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> []byte {
|
||||
str := s
|
||||
|
||||
+20
-39
@@ -16,8 +16,8 @@ reader_init :: proc(r: ^Reader, s: []byte) {
|
||||
}
|
||||
|
||||
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = r
|
||||
s.stream_vtable = &_reader_vtable
|
||||
s.data = r
|
||||
s.procedure = _reader_proc
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,41 +137,22 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
|
||||
|
||||
@(private)
|
||||
_reader_vtable := io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_size(r)
|
||||
},
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read(r, p)
|
||||
},
|
||||
impl_read_at = proc(s: io.Stream, p: []byte, off: i64) -> (n: int, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read_at(r, p, off)
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read_byte(r)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_unread_byte(r)
|
||||
},
|
||||
impl_read_rune = proc(s: io.Stream) -> (ch: rune, size: int, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_read_rune(r)
|
||||
},
|
||||
impl_unread_rune = proc(s: io.Stream) -> io.Error {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_unread_rune(r)
|
||||
},
|
||||
impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_seek(r, offset, whence)
|
||||
},
|
||||
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_write_to(r, w)
|
||||
},
|
||||
_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
r := (^Reader)(stream_data)
|
||||
#partial switch mode {
|
||||
case .Read:
|
||||
return io._i64_err(reader_read(r, p))
|
||||
case .Read_At:
|
||||
return io._i64_err(reader_read_at(r, p, offset))
|
||||
case .Seek:
|
||||
n, err = reader_seek(r, offset, whence)
|
||||
return
|
||||
case .Size:
|
||||
n = reader_size(r)
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Read_At, .Seek, .Size, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package c
|
||||
|
||||
import builtin "core:builtin"
|
||||
import builtin "base:builtin"
|
||||
|
||||
char :: builtin.u8 // assuming -funsigned-char
|
||||
|
||||
|
||||
@@ -1118,7 +1118,7 @@ expand_macro :: proc(cpp: ^Preprocessor, rest: ^^Token, tok: ^Token) -> bool {
|
||||
|
||||
search_include_next :: proc(cpp: ^Preprocessor, filename: string) -> (path: string, ok: bool) {
|
||||
for ; cpp.include_next_index < len(cpp.include_paths); cpp.include_next_index += 1 {
|
||||
tpath := filepath.join(elems={cpp.include_paths[cpp.include_next_index], filename}, allocator=context.temp_allocator)
|
||||
tpath := filepath.join({cpp.include_paths[cpp.include_next_index], filename}, allocator=context.temp_allocator)
|
||||
if os.exists(tpath) {
|
||||
return strings.clone(tpath), true
|
||||
}
|
||||
@@ -1136,7 +1136,7 @@ search_include_paths :: proc(cpp: ^Preprocessor, filename: string) -> (path: str
|
||||
}
|
||||
|
||||
for include_path in cpp.include_paths {
|
||||
tpath := filepath.join(elems={include_path, filename}, allocator=context.temp_allocator)
|
||||
tpath := filepath.join({include_path, filename}, allocator=context.temp_allocator)
|
||||
if os.exists(tpath) {
|
||||
path, ok = strings.clone(tpath), true
|
||||
cpp.filepath_cache[filename] = path
|
||||
|
||||
@@ -127,7 +127,7 @@ advance_rune :: proc(t: ^Tokenizer) {
|
||||
}
|
||||
|
||||
advance_rune_n :: proc(t: ^Tokenizer, n: int) {
|
||||
for in 0..<n {
|
||||
for _ in 0..<n {
|
||||
advance_rune(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ foreign libc {
|
||||
crealf :: proc(z: complex_float) -> float ---
|
||||
}
|
||||
|
||||
import builtin "core:builtin"
|
||||
import builtin "base:builtin"
|
||||
|
||||
complex_float :: distinct builtin.complex64
|
||||
complex_double :: distinct builtin.complex128
|
||||
|
||||
@@ -2,7 +2,7 @@ package libc
|
||||
|
||||
// 7.12 Mathematics
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
|
||||
@@ -63,4 +63,4 @@ foreign libc {
|
||||
// strictly conformant C implementation is 16 on the platforms we care about.
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
jmp_buf :: struct #align 16 { _: [4096]char, }
|
||||
jmp_buf :: struct #align(16) { _: [4096]char, }
|
||||
|
||||
@@ -2,7 +2,7 @@ package libc
|
||||
|
||||
// 7.16 Variable arguments
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
@(private="file")
|
||||
@(default_calling_convention="none")
|
||||
@@ -18,7 +18,7 @@ foreign _ {
|
||||
// strictly conformant C implementation is 16 on the platforms we care about.
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
va_list :: struct #align 16 {
|
||||
va_list :: struct #align(16) {
|
||||
_: [4096]u8,
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package libc
|
||||
|
||||
// 7.17 Atomics
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
ATOMIC_BOOL_LOCK_FREE :: true
|
||||
ATOMIC_CHAR_LOCK_FREE :: true
|
||||
|
||||
+102
-1
@@ -1,5 +1,7 @@
|
||||
package libc
|
||||
|
||||
import "core:io"
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc {
|
||||
"system:libucrt.lib",
|
||||
@@ -182,7 +184,7 @@ foreign libc {
|
||||
fscanf :: proc(stream: ^FILE, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
printf :: proc(format: cstring, #c_vararg args: ..any) -> int ---
|
||||
scanf :: proc(format: cstring, #c_vararg args: ..any) -> int ---
|
||||
snprintf :: proc(s: [^]char, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
snprintf :: proc(s: [^]char, n: size_t, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
sscanf :: proc(s, format: cstring, #c_vararg args: ..any) -> int ---
|
||||
vfprintf :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---
|
||||
vfscanf :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---
|
||||
@@ -218,3 +220,102 @@ foreign libc {
|
||||
ferror :: proc(stream: ^FILE) -> int ---
|
||||
perror :: proc(s: cstring) ---
|
||||
}
|
||||
|
||||
to_stream :: proc(file: ^FILE) -> io.Stream {
|
||||
stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
|
||||
unknown_or_eof :: proc(f: ^FILE) -> io.Error {
|
||||
switch {
|
||||
case ferror(f) != 0:
|
||||
return .Unknown
|
||||
case feof(f) != 0:
|
||||
return .EOF
|
||||
case:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
file := (^FILE)(stream_data)
|
||||
switch mode {
|
||||
case .Close:
|
||||
if fclose(file) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
case .Flush:
|
||||
if fflush(file) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
case .Read:
|
||||
n = i64(fread(raw_data(p), size_of(byte), len(p), file))
|
||||
if n == 0 { err = unknown_or_eof(file) }
|
||||
|
||||
case .Read_At:
|
||||
curr := ftell(file)
|
||||
if curr == -1 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
if fseek(file, long(offset), SEEK_SET) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
defer fseek(file, long(curr), SEEK_SET)
|
||||
|
||||
n = i64(fread(raw_data(p), size_of(byte), len(p), file))
|
||||
if n == 0 { err = unknown_or_eof(file) }
|
||||
|
||||
case .Write:
|
||||
n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
|
||||
if n == 0 { err = unknown_or_eof(file) }
|
||||
|
||||
case .Write_At:
|
||||
curr := ftell(file)
|
||||
if curr == -1 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
if fseek(file, long(offset), SEEK_SET) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
defer fseek(file, long(curr), SEEK_SET)
|
||||
|
||||
n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
|
||||
if n == 0 { err = unknown_or_eof(file) }
|
||||
|
||||
case .Seek:
|
||||
if fseek(file, long(offset), int(whence)) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
case .Size:
|
||||
curr := ftell(file)
|
||||
if curr == -1 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
defer fseek(file, curr, SEEK_SET)
|
||||
|
||||
if fseek(file, 0, SEEK_END) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
n = i64(ftell(file))
|
||||
if n == -1 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
case .Destroy:
|
||||
return 0, .Empty
|
||||
|
||||
case .Query:
|
||||
return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return {
|
||||
data = file,
|
||||
procedure = stream_proc,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package libc
|
||||
|
||||
import "core:runtime"
|
||||
import "base:runtime"
|
||||
|
||||
// 7.24 String handling
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ when ODIN_OS == .Windows {
|
||||
@(link_name="_Cnd_destroy") cnd_destroy :: proc(cond: ^cnd_t) ---
|
||||
@(link_name="_Cnd_init") cnd_init :: proc(cond: ^cnd_t) -> int ---
|
||||
@(link_name="_Cnd_signal") cnd_signal :: proc(cond: ^cnd_t) -> int ---
|
||||
@(link_name="_Cnd_timedwait") cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
|
||||
@(link_name="_Cnd_timedwait") cnd_timedwait :: proc(cond: ^cnd_t, mtx: ^mtx_t, ts: ^timespec) -> int ---
|
||||
@(link_name="_Cnd_wait") cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
||||
|
||||
// 7.26.4 Mutex functions
|
||||
|
||||
@@ -35,12 +35,12 @@ when ODIN_OS == .Windows {
|
||||
clock_t :: distinct long
|
||||
time_t :: distinct i64
|
||||
|
||||
timespec :: struct #align 8 {
|
||||
timespec :: struct #align(8) {
|
||||
tv_sec: time_t,
|
||||
tv_nsec: long,
|
||||
}
|
||||
|
||||
tm :: struct #align 8 {
|
||||
tm :: struct #align(8) {
|
||||
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package libc
|
||||
|
||||
import "core:c"
|
||||
|
||||
#assert(!ODIN_NO_CRT, `"core:c/libc" cannot be imported when '-no-crt' is used`)
|
||||
|
||||
char :: c.char // assuming -funsigned-char
|
||||
|
||||
schar :: c.schar
|
||||
|
||||
@@ -98,7 +98,7 @@ foreign libc {
|
||||
}
|
||||
|
||||
// Large enough and aligned enough for any wide-spread in-use libc.
|
||||
mbstate_t :: struct #align 16 { _: [32]char, }
|
||||
mbstate_t :: struct #align(16) { _: [32]char, }
|
||||
|
||||
// Odin does not have default argument promotion so the need for a separate type
|
||||
// here isn't necessary, though make it distinct just to be safe.
|
||||
|
||||
+53
-82
@@ -12,7 +12,7 @@ package compress
|
||||
|
||||
import "core:io"
|
||||
import "core:bytes"
|
||||
import "core:runtime"
|
||||
import "base:runtime"
|
||||
|
||||
/*
|
||||
These settings bound how much compression algorithms will allocate for their output buffer.
|
||||
@@ -20,10 +20,9 @@ import "core:runtime"
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
When a decompression routine doesn't stream its output, but writes to a buffer,
|
||||
we pre-allocate an output buffer to speed up decompression. The default is 1 MiB.
|
||||
*/
|
||||
|
||||
// When a decompression routine doesn't stream its output, but writes to a buffer,
|
||||
// we pre-allocate an output buffer to speed up decompression. The default is 1 MiB.
|
||||
COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 20))
|
||||
|
||||
/*
|
||||
@@ -34,16 +33,14 @@ COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 2
|
||||
|
||||
*/
|
||||
when size_of(uintptr) == 8 {
|
||||
/*
|
||||
For 64-bit platforms, we set the default max buffer size to 4 GiB,
|
||||
which is GZIP and PKZIP's max payload size.
|
||||
*/
|
||||
|
||||
// For 64-bit platforms, we set the default max buffer size to 4 GiB,
|
||||
// which is GZIP and PKZIP's max payload size.
|
||||
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 32))
|
||||
} else {
|
||||
/*
|
||||
For 32-bit platforms, we set the default max buffer size to 512 MiB.
|
||||
*/
|
||||
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29))
|
||||
|
||||
// For 32-bit platforms, we set the default max buffer size to 512 MiB.
|
||||
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29))
|
||||
}
|
||||
|
||||
|
||||
@@ -69,9 +66,8 @@ General_Error :: enum {
|
||||
Incompatible_Options,
|
||||
Unimplemented,
|
||||
|
||||
/*
|
||||
Memory errors
|
||||
*/
|
||||
// Memory errors
|
||||
|
||||
Allocation_Failed,
|
||||
Resize_Failed,
|
||||
}
|
||||
@@ -86,17 +82,16 @@ GZIP_Error :: enum {
|
||||
Payload_Length_Invalid,
|
||||
Payload_CRC_Invalid,
|
||||
|
||||
/*
|
||||
GZIP's payload can be a maximum of max(u32le), or 4 GiB.
|
||||
If you tell it you expect it to contain more, that's obviously an error.
|
||||
*/
|
||||
Payload_Size_Exceeds_Max_Payload,
|
||||
/*
|
||||
For buffered instead of streamed output, the payload size can't exceed
|
||||
the max set by the `COMPRESS_OUTPUT_ALLOCATE_MAX` switch in compress/common.odin.
|
||||
// GZIP's payload can be a maximum of max(u32le), or 4 GiB.
|
||||
// If you tell it you expect it to contain more, that's obviously an error.
|
||||
|
||||
Payload_Size_Exceeds_Max_Payload,
|
||||
|
||||
// For buffered instead of streamed output, the payload size can't exceed
|
||||
// the max set by the `COMPRESS_OUTPUT_ALLOCATE_MAX` switch in compress/common.odin.
|
||||
//
|
||||
// You can tweak this setting using `-define:COMPRESS_OUTPUT_ALLOCATE_MAX=size_in_bytes`
|
||||
|
||||
You can tweak this setting using `-define:COMPRESS_OUTPUT_ALLOCATE_MAX=size_in_bytes`
|
||||
*/
|
||||
Output_Exceeds_COMPRESS_OUTPUT_ALLOCATE_MAX,
|
||||
|
||||
}
|
||||
@@ -137,9 +132,8 @@ Context_Memory_Input :: struct #packed {
|
||||
code_buffer: u64,
|
||||
num_bits: u64,
|
||||
|
||||
/*
|
||||
If we know the data size, we can optimize the reads and writes.
|
||||
*/
|
||||
// If we know the data size, we can optimize the reads and writes.
|
||||
|
||||
size_packed: i64,
|
||||
size_unpacked: i64,
|
||||
}
|
||||
@@ -159,18 +153,16 @@ Context_Stream_Input :: struct #packed {
|
||||
code_buffer: u64,
|
||||
num_bits: u64,
|
||||
|
||||
/*
|
||||
If we know the data size, we can optimize the reads and writes.
|
||||
*/
|
||||
// If we know the data size, we can optimize the reads and writes.
|
||||
|
||||
size_packed: i64,
|
||||
size_unpacked: i64,
|
||||
|
||||
/*
|
||||
Flags:
|
||||
`input_fully_in_memory`
|
||||
true = This tells us we read input from `input_data` exclusively. [] = EOF.
|
||||
false = Try to refill `input_data` from the `input` stream.
|
||||
*/
|
||||
// Flags:
|
||||
// `input_fully_in_memory`
|
||||
// true = This tells us we read input from `input_data` exclusively. [] = EOF.
|
||||
// false = Try to refill `input_data` from the `input` stream.
|
||||
|
||||
input_fully_in_memory: b8,
|
||||
|
||||
padding: [1]u8,
|
||||
@@ -188,7 +180,8 @@ input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Erro
|
||||
}
|
||||
|
||||
input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Error) {
|
||||
return io.size(z.input), nil
|
||||
res, _ = io.size(z.input)
|
||||
return
|
||||
}
|
||||
|
||||
input_size :: proc{input_size_from_memory, input_size_from_stream}
|
||||
@@ -212,25 +205,19 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
|
||||
// TODO: REMOVE ALL USE OF context.temp_allocator here
|
||||
// there is literally no need for it
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
_, e := z.input->impl_read(b[:])
|
||||
if e == .None {
|
||||
return b, .None
|
||||
}
|
||||
|
||||
return []u8{}, e
|
||||
_ = io.read(z.input, b[:]) or_return
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
|
||||
b, e := read_slice(z, size_of(T))
|
||||
if e == .None {
|
||||
return (^T)(&b[0])^, .None
|
||||
}
|
||||
|
||||
return T{}, e
|
||||
b := read_slice(z, size_of(T)) or_return
|
||||
return (^T)(&b[0])^, nil
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
@@ -247,20 +234,14 @@ read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8,
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
|
||||
b, e := read_slice_from_stream(z, 1)
|
||||
if e == .None {
|
||||
return b[0], .None
|
||||
}
|
||||
|
||||
return 0, e
|
||||
b := read_slice_from_stream(z, 1) or_return
|
||||
return b[0], nil
|
||||
}
|
||||
|
||||
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
|
||||
|
||||
/*
|
||||
You would typically only use this at the end of Inflate, to drain bits from the code buffer
|
||||
preferentially.
|
||||
*/
|
||||
// You would typically only use this at the end of Inflate, to drain bits from the code buffer
|
||||
// preferentially.
|
||||
@(optimization_mode="speed")
|
||||
read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: io.Error) {
|
||||
if z.num_bits >= 8 {
|
||||
@@ -317,12 +298,9 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
size :: size_of(T)
|
||||
|
||||
// Get current position to read from.
|
||||
curr, e1 := z.input->impl_seek(0, .Current)
|
||||
if e1 != .None {
|
||||
return T{}, e1
|
||||
}
|
||||
r, e2 := io.to_reader_at(z.input)
|
||||
if !e2 {
|
||||
curr := z.input->impl_seek(0, .Current) or_return
|
||||
r, e1 := io.to_reader_at(z.input)
|
||||
if !e1 {
|
||||
return T{}, .Empty
|
||||
}
|
||||
when size <= 128 {
|
||||
@@ -330,8 +308,8 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
} else {
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
}
|
||||
_, e3 := io.read_at(r, b[:], curr)
|
||||
if e3 != .None {
|
||||
_, e2 := io.read_at(r, b[:], curr)
|
||||
if e2 != .None {
|
||||
return T{}, .Empty
|
||||
}
|
||||
|
||||
@@ -344,16 +322,9 @@ peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input,
|
||||
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
|
||||
}
|
||||
|
||||
cur_pos := z.input->impl_seek(0, .Current) or_return
|
||||
// Seek to offset.
|
||||
pos, e2 := z.input->impl_seek(offset, .Start)
|
||||
if e2 != .None {
|
||||
return T{}, e2
|
||||
}
|
||||
pos := z.input->impl_seek(offset, .Start) or_return
|
||||
|
||||
r, e3 := io.to_reader_at(z.input)
|
||||
if !e3 {
|
||||
@@ -462,7 +433,7 @@ peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width:
|
||||
if z.num_bits < u64(width) {
|
||||
refill_lsb(z)
|
||||
}
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
@@ -470,7 +441,7 @@ peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width:
|
||||
if z.num_bits < u64(width) {
|
||||
refill_lsb(z)
|
||||
}
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
|
||||
@@ -478,13 +449,13 @@ peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
|
||||
@(optimization_mode="speed")
|
||||
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
|
||||
assert(z.num_bits >= u64(width))
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
|
||||
assert(z.num_bits >= u64(width))
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
|
||||
|
||||
@@ -335,10 +335,8 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
|
||||
|
||||
// fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size);
|
||||
|
||||
zlib_error := zlib.inflate_raw(z=z, expected_output_size=expected_output_size)
|
||||
if zlib_error != nil {
|
||||
return zlib_error
|
||||
}
|
||||
zlib.inflate_raw(z, expected_output_size=expected_output_size) or_return
|
||||
|
||||
/*
|
||||
Read CRC32 using the ctx bit reader because zlib may leave bytes in there.
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// package shoco is an implementation of the shoco short string compressor
|
||||
package shoco
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
import "core:compress"
|
||||
|
||||
Shoco_Pack :: struct {
|
||||
@@ -177,12 +177,10 @@ decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocato
|
||||
max_output_size := decompress_bound(len(input), model)
|
||||
|
||||
buf: [dynamic]u8
|
||||
if !resize(&buf, max_output_size) {
|
||||
return "", .Out_Of_Memory
|
||||
}
|
||||
resize(&buf, max_output_size) or_return
|
||||
|
||||
length, result := decompress_slice_to_output_buffer(input, buf[:])
|
||||
resize(&buf, length)
|
||||
resize(&buf, length) or_return
|
||||
return string(buf[:]), result
|
||||
}
|
||||
decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
|
||||
@@ -307,12 +305,10 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
|
||||
max_output_size := compress_bound(len(input))
|
||||
|
||||
buf: [dynamic]u8
|
||||
if !resize(&buf, max_output_size) {
|
||||
return {}, .Out_Of_Memory
|
||||
}
|
||||
resize(&buf, max_output_size) or_return
|
||||
|
||||
length, result := compress_string_to_buffer(input, buf[:])
|
||||
resize(&buf, length)
|
||||
resize(&buf, length) or_return
|
||||
return buf[:length], result
|
||||
}
|
||||
compress :: proc{compress_string_to_buffer, compress_string}
|
||||
@@ -1,3 +1,4 @@
|
||||
//+vet !using-param
|
||||
package zlib
|
||||
|
||||
/*
|
||||
@@ -146,15 +147,7 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
|
||||
Double until we reach the maximum allowed.
|
||||
*/
|
||||
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX)
|
||||
resize(buf, new_size)
|
||||
if len(buf) != new_size {
|
||||
/*
|
||||
Resize failed.
|
||||
*/
|
||||
return .Resize_Failed
|
||||
}
|
||||
|
||||
return nil
|
||||
return resize(buf, new_size)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -181,7 +174,7 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
|
||||
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
|
||||
/*
|
||||
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
|
||||
without having to worry about wrapping, so no need for a temp allocation to give to
|
||||
@@ -305,10 +298,10 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
||||
code := u16(compress.peek_bits_lsb(z,16))
|
||||
|
||||
k := int(z_bit_reverse(code, 16))
|
||||
s: u8
|
||||
|
||||
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
|
||||
if k < t.maxcode[s] {
|
||||
s: u8 = HUFFMAN_FAST_BITS+1
|
||||
for {
|
||||
#no_bounds_check if k < t.maxcode[s] {
|
||||
break
|
||||
}
|
||||
s += 1
|
||||
@@ -471,7 +464,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
||||
}
|
||||
|
||||
// Parse ZLIB stream without header.
|
||||
inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return
|
||||
inflate_raw(ctx, expected_output_size=expected_output_size) or_return
|
||||
|
||||
if !raw {
|
||||
compress.discard_to_next_byte_lsb(ctx)
|
||||
@@ -509,8 +502,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
/*
|
||||
Try to pre-allocate the output buffer.
|
||||
*/
|
||||
reserve(&z.output.buf, expected_output_size)
|
||||
resize (&z.output.buf, expected_output_size)
|
||||
reserve(&z.output.buf, expected_output_size) or_return
|
||||
resize (&z.output.buf, expected_output_size) or_return
|
||||
}
|
||||
|
||||
if len(z.output.buf) != expected_output_size {
|
||||
@@ -653,7 +646,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
}
|
||||
|
||||
if int(z.bytes_written) != len(z.output.buf) {
|
||||
resize(&z.output.buf, int(z.bytes_written))
|
||||
resize(&z.output.buf, int(z.bytes_written)) or_return
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -665,7 +658,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e
|
||||
ctx.input_data = input
|
||||
ctx.output = buf
|
||||
|
||||
return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size)
|
||||
return inflate_from_context(&ctx, raw=raw, expected_output_size=expected_output_size)
|
||||
}
|
||||
|
||||
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
|
||||
@@ -674,7 +667,7 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
|
||||
ctx.input_data = input
|
||||
ctx.output = buf
|
||||
|
||||
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
||||
return inflate_raw(&ctx, expected_output_size=expected_output_size)
|
||||
}
|
||||
|
||||
inflate :: proc{inflate_from_context, inflate_from_byte_array}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dynamic_bit_array
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
import "core:mem"
|
||||
|
||||
/*
|
||||
@@ -27,27 +27,28 @@ Bit_Array_Iterator :: struct {
|
||||
word_idx: int,
|
||||
bit_idx: uint,
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - the array to iterate over
|
||||
Wraps a `Bit_Array` into an Iterator
|
||||
|
||||
Out:
|
||||
- it: ^Bit_Array_Iterator - the iterator that holds iteration state
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
|
||||
Returns:
|
||||
- it: Iterator struct
|
||||
*/
|
||||
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.
|
||||
Returns the next bit, including its set-state. ok=false once exhausted
|
||||
|
||||
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
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
|
||||
Returns:
|
||||
- set: `true` if the bit at `index` is set.
|
||||
- index: The next bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
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
|
||||
@@ -64,39 +65,51 @@ iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok:
|
||||
|
||||
return set, index, true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||
Returns the next Set Bit, for example if `0b1010`, then the iterator will return index={1, 3} over two calls.
|
||||
|
||||
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
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
|
||||
Returns:
|
||||
- index: The next *set* bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
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.
|
||||
Returns the next Unset Bit, for example if `0b1010`, then the iterator will return index={0, 2} over two calls.
|
||||
|
||||
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
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
|
||||
Returns:
|
||||
- index: The next *unset* bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||
return iterate_internal_(it, false)
|
||||
}
|
||||
/*
|
||||
Iterates through set/unset bits
|
||||
|
||||
*Private*
|
||||
|
||||
Inputs:
|
||||
- it: The iterator that holds the state.
|
||||
- ITERATE_SET_BITS: `true` for returning only set bits, false for returning only unset bits
|
||||
|
||||
Returns:
|
||||
- index: The next *unset* bit of the Bit_Array referenced by `it`.
|
||||
- ok: `true` if the iterator can continue, `false` if the iterator is done
|
||||
*/
|
||||
@(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,
|
||||
// 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 {
|
||||
@@ -106,14 +119,14 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
|
||||
@@ -124,24 +137,21 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
|
||||
}
|
||||
return index, index <= it.array.max_index
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
Gets the state of a bit in the bit-array
|
||||
|
||||
Out:
|
||||
- res: The bit you're interested in.
|
||||
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
|
||||
The `ok` return value may be ignored.
|
||||
Returns:
|
||||
- res: `true` if the bit at `index` is set.
|
||||
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
|
||||
*/
|
||||
get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
|
||||
get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #optional_ok {
|
||||
idx := int(index) - ba.bias
|
||||
|
||||
if ba == nil || int(index) < ba.bias { return false, false }
|
||||
context.allocator = allocator
|
||||
|
||||
leg_index := idx >> INDEX_SHIFT
|
||||
bit_index := idx & INDEX_MASK
|
||||
@@ -157,18 +167,36 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
Gets the state of a bit in the bit-array
|
||||
|
||||
Out:
|
||||
- ok: Whether or not we managed to set requested bit.
|
||||
*Bypasses all Checks*
|
||||
|
||||
`set` automatically resizes the Bit Array to accommodate the requested index if needed.
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
|
||||
Returns:
|
||||
- `true` if bit is set
|
||||
*/
|
||||
set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||
unsafe_get :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint) -> bool #no_bounds_check {
|
||||
return bool((ba.bits[index >> INDEX_SHIFT] >> uint(index & INDEX_MASK)) & 1)
|
||||
}
|
||||
/*
|
||||
Sets the state of a bit in the bit-array
|
||||
|
||||
*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
- set_to: `true` sets the bit on, `false` to turn it off
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- ok: Whether the set was successful, `false` on allocation failure or bad index
|
||||
*/
|
||||
set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator := context.allocator) -> (ok: bool) {
|
||||
|
||||
idx := int(index) - ba.bias
|
||||
|
||||
@@ -181,65 +209,97 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
||||
resize_if_needed(ba, leg_index) or_return
|
||||
|
||||
ba.max_index = max(idx, ba.max_index)
|
||||
ba.bits[leg_index] |= 1 << uint(bit_index)
|
||||
|
||||
if set_to{ ba.bits[leg_index] |= 1 << uint(bit_index) }
|
||||
else { ba.bits[leg_index] &= ~(1 << uint(bit_index)) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
In:
|
||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||
- index: The bit index. Can be an enum member.
|
||||
Sets the state of a bit in the bit-array
|
||||
|
||||
Out:
|
||||
- ok: Whether or not we managed to unset requested bit.
|
||||
*Bypasses all checks*
|
||||
|
||||
`unset` automatically resizes the Bit Array to accommodate the requested index if needed.
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
*/
|
||||
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
|
||||
unsafe_set :: proc(ba: ^Bit_Array, bit: int) #no_bounds_check {
|
||||
ba.bits[bit >> INDEX_SHIFT] |= 1 << uint(bit & INDEX_MASK)
|
||||
}
|
||||
|
||||
/*
|
||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||
Unsets the state of a bit in the bit-array. (Convienence wrapper for `set`)
|
||||
|
||||
*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- ok: Whether the unset was successful, `false` on allocation failure or bad index
|
||||
*/
|
||||
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
|
||||
unset :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
|
||||
return set(ba, index, false, allocator)
|
||||
}
|
||||
/*
|
||||
Unsets the state of a bit in the bit-array
|
||||
|
||||
*Bypasses all Checks*
|
||||
|
||||
Inputs:
|
||||
- ba: Pointer to the Bit_Array
|
||||
- index: Which bit in the array
|
||||
*/
|
||||
unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
|
||||
b.bits[bit >> INDEX_SHIFT] &= ~(1 << uint(bit & INDEX_MASK))
|
||||
}
|
||||
/*
|
||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||
|
||||
*Allocates (`new(Bit_Array) & make(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
- max_index: maximum starting index
|
||||
- min_index: minimum starting index (used as a bias)
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- ba: Allocates a bit_Array, backing data is set to `max-min / 64` indices, rounded up (eg 65 - 0 allocates for [2]u64).
|
||||
*/
|
||||
create :: proc(max_index: int, min_index: int = 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
|
||||
context.allocator = allocator
|
||||
size_in_bits := max_index - min_index
|
||||
|
||||
if size_in_bits < 1 { return {}, false }
|
||||
|
||||
legs := size_in_bits >> INDEX_SHIFT
|
||||
|
||||
if size_in_bits & INDEX_MASK > 0 {legs+=1}
|
||||
bits, err := make([dynamic]u64, legs)
|
||||
ok = err == mem.Allocator_Error.None
|
||||
res = new(Bit_Array)
|
||||
res.bits = bits
|
||||
res.bias = min_index
|
||||
res.max_index = max_index
|
||||
res.free_pointer = true
|
||||
return res, resize_if_needed(res, legs)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Sets all bits to `false`.
|
||||
Sets all values in the Bit_Array to zero.
|
||||
|
||||
Inputs:
|
||||
- ba: The target Bit_Array
|
||||
*/
|
||||
clear :: proc(ba: ^Bit_Array) {
|
||||
if ba == nil { return }
|
||||
mem.zero_slice(ba.bits[:])
|
||||
}
|
||||
|
||||
/*
|
||||
Releases the memory used by the Bit Array.
|
||||
Deallocates the Bit_Array and its backing storage
|
||||
|
||||
Inputs:
|
||||
- ba: The target Bit_Array
|
||||
*/
|
||||
destroy :: proc(ba: ^Bit_Array) {
|
||||
if ba == nil { return }
|
||||
@@ -248,9 +308,8 @@ destroy :: proc(ba: ^Bit_Array) {
|
||||
free(ba)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Resizes the Bit Array. For internal use.
|
||||
Resizes the Bit Array. For internal use. Provisions needed capacity+1
|
||||
If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
|
||||
*/
|
||||
@(private="file")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package container_intrusive_list
|
||||
|
||||
import "core:intrinsics"
|
||||
import "base:intrinsics"
|
||||
|
||||
// An intrusive doubly-linked list
|
||||
//
|
||||
@@ -20,10 +20,10 @@ List :: struct {
|
||||
|
||||
|
||||
Node :: struct {
|
||||
next, prev: ^Node,
|
||||
prev, next: ^Node,
|
||||
}
|
||||
|
||||
push_front :: proc(list: ^List, node: ^Node) {
|
||||
push_front :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if list.head != nil {
|
||||
list.head.prev = node
|
||||
node.prev, node.next = nil, list.head
|
||||
@@ -34,7 +34,7 @@ push_front :: proc(list: ^List, node: ^Node) {
|
||||
}
|
||||
}
|
||||
|
||||
push_back :: proc(list: ^List, node: ^Node) {
|
||||
push_back :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if list.tail != nil {
|
||||
list.tail.next = node
|
||||
node.prev, node.next = list.tail, nil
|
||||
@@ -45,7 +45,7 @@ push_back :: proc(list: ^List, node: ^Node) {
|
||||
}
|
||||
}
|
||||
|
||||
remove :: proc(list: ^List, node: ^Node) {
|
||||
remove :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if node != nil {
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
@@ -83,12 +83,34 @@ remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
|
||||
}
|
||||
}
|
||||
|
||||
remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^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 {
|
||||
|
||||
|
||||
is_empty :: proc "contextless" (list: ^List) -> bool {
|
||||
return list.head == nil
|
||||
}
|
||||
|
||||
pop_front :: proc(list: ^List) -> ^Node {
|
||||
pop_front :: proc "contextless" (list: ^List) -> ^Node {
|
||||
link := list.head
|
||||
if link == nil {
|
||||
return nil
|
||||
@@ -108,7 +130,7 @@ pop_front :: proc(list: ^List) -> ^Node {
|
||||
return link
|
||||
|
||||
}
|
||||
pop_back :: proc(list: ^List) -> ^Node {
|
||||
pop_back :: proc "contextless" (list: ^List) -> ^Node {
|
||||
link := list.tail
|
||||
if link == nil {
|
||||
return nil
|
||||
@@ -134,25 +156,25 @@ Iterator :: struct($T: typeid) {
|
||||
offset: uintptr,
|
||||
}
|
||||
|
||||
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
iterator_head :: proc "contextless" (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)
|
||||
iterator_tail :: proc "contextless" (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)
|
||||
iterator_from_node :: proc "contextless" (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) {
|
||||
iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
@@ -162,7 +184,7 @@ iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
return (^T)(uintptr(node) - it.offset), true
|
||||
}
|
||||
|
||||
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package container_lru
|
||||
|
||||
import "core:runtime"
|
||||
import "core:intrinsics"
|
||||
import "base:runtime"
|
||||
import "base:intrinsics"
|
||||
_ :: runtime
|
||||
_ :: intrinsics
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package container_priority_queue
|
||||
|
||||
import "core:builtin"
|
||||
import "base:builtin"
|
||||
|
||||
Priority_Queue :: struct($T: typeid) {
|
||||
queue: [dynamic]T,
|
||||
@@ -140,3 +140,18 @@ remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
peek_safe :: proc(pq: $Q/Priority_Queue($T), loc := #caller_location) -> (res: T, ok: bool) {
|
||||
if builtin.len(pq.queue) > 0 {
|
||||
return pq.queue[0], true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
peek :: proc(pq: $Q/Priority_Queue($T), loc := #caller_location) -> (res: T) {
|
||||
assert(condition=builtin.len(pq.queue)>0, loc=loc)
|
||||
|
||||
if builtin.len(pq.queue) > 0 {
|
||||
return pq.queue[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package container_queue
|
||||
|
||||
import "core:builtin"
|
||||
import "core:runtime"
|
||||
import "base:builtin"
|
||||
import "base:runtime"
|
||||
_ :: runtime
|
||||
|
||||
// Dynamically resizable double-ended queue/ring-buffer
|
||||
@@ -14,7 +14,7 @@ Queue :: struct($T: typeid) {
|
||||
DEFAULT_CAPACITY :: 16
|
||||
|
||||
// Procedure to initialize a queue
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool {
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error {
|
||||
if q.data.allocator.procedure == nil {
|
||||
q.data.allocator = allocator
|
||||
}
|
||||
@@ -22,7 +22,9 @@ init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := contex
|
||||
return reserve(q, capacity)
|
||||
}
|
||||
|
||||
// Procedure to initialize a queue from a fixed backing slice
|
||||
// Procedure to initialize a queue from a fixed backing slice.
|
||||
// The contents of the `backing` will be overwritten as items are pushed onto the `Queue`.
|
||||
// Any previous contents are not available.
|
||||
init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
|
||||
clear(q)
|
||||
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
|
||||
@@ -34,6 +36,21 @@ init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Procedure to initialize a queue from a fixed backing slice.
|
||||
// Existing contents are preserved and available on the queue.
|
||||
init_with_contents :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
|
||||
clear(q)
|
||||
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
|
||||
data = raw_data(backing),
|
||||
len = builtin.len(backing),
|
||||
cap = builtin.len(backing),
|
||||
allocator = {procedure=runtime.nil_allocator_proc, data=nil},
|
||||
}
|
||||
q.len = len(backing)
|
||||
q.offset = len(backing)
|
||||
return true
|
||||
}
|
||||
|
||||
// Procedure to destroy a queue
|
||||
destroy :: proc(q: ^$Q/Queue($T)) {
|
||||
delete(q.data)
|
||||
@@ -55,11 +72,11 @@ space :: proc(q: $Q/Queue($T)) -> int {
|
||||
}
|
||||
|
||||
// Reserve enough space for at least the specified capacity
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool {
|
||||
if uint(capacity) > q.len {
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
|
||||
if capacity > space(q^) {
|
||||
return _grow(q, uint(capacity))
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -112,25 +129,25 @@ peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||
}
|
||||
|
||||
// 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) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
}
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
q.data[idx] = elem
|
||||
q.len += 1
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Push an element to the front of the queue
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
}
|
||||
q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
|
||||
q.len += 1
|
||||
q.data[q.offset] = elem
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +190,7 @@ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||
}
|
||||
|
||||
// Push multiple elements to the front of the queue
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
n := uint(builtin.len(elems))
|
||||
if space(q^) < int(n) {
|
||||
_grow(q, q.len + n) or_return
|
||||
@@ -188,7 +205,7 @@ push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
|
||||
copy(q.data[insert_from:], elems[:insert_to])
|
||||
copy(q.data[:insert_from], elems[insert_to:])
|
||||
q.len += n
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Consume `n` elements from the front of the queue
|
||||
@@ -225,7 +242,7 @@ clear :: proc(q: ^$Q/Queue($T)) {
|
||||
|
||||
|
||||
// Internal growinh procedure
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error {
|
||||
new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
|
||||
n := uint(builtin.len(q.data))
|
||||
builtin.resize(&q.data, int(new_capacity)) or_return
|
||||
@@ -234,5 +251,5 @@ _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
|
||||
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
|
||||
q.offset += new_capacity - n
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package container_small_array
|
||||
|
||||
import "core:builtin"
|
||||
import "core:runtime"
|
||||
import "base:builtin"
|
||||
import "base:runtime"
|
||||
_ :: runtime
|
||||
|
||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// map type is being used to accelerate lookups.
|
||||
package container_topological_sort
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
_ :: intrinsics
|
||||
_ :: runtime
|
||||
|
||||
@@ -32,7 +32,7 @@ init :: proc(sorter: ^$S/Sorter($K)) {
|
||||
}
|
||||
|
||||
destroy :: proc(sorter: ^$S/Sorter($K)) {
|
||||
for _, v in &sorter.relations {
|
||||
for _, v in sorter.relations {
|
||||
delete(v.dependents)
|
||||
}
|
||||
delete(sorter.relations)
|
||||
@@ -80,11 +80,13 @@ sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]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 root in sorted {
|
||||
for k, _ in relations[root].dependents {
|
||||
relation := &relations[k]
|
||||
relation.dependencies -= 1
|
||||
if relation.dependencies == 0 {
|
||||
append(&sorted, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+42
-51
@@ -1,95 +1,86 @@
|
||||
# crypto
|
||||
A crypto library for the Odin language
|
||||
|
||||
A cryptography library for the Odin language
|
||||
|
||||
## Supported
|
||||
|
||||
This library offers various algorithms implemented in Odin.
|
||||
Please see the chart below for the options.
|
||||
Please see the chart below for some of the options.
|
||||
|
||||
## Hashing algorithms
|
||||
|
||||
| Algorithm | |
|
||||
|:-------------------------------------------------------------------------------------------------------------|:-----------------|
|
||||
| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | ✔️ |
|
||||
| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ |
|
||||
| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | ✔️ |
|
||||
| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | ✔️ |
|
||||
| [Grøstl](http://www.groestl.info/Groestl.zip) | ✔️ |
|
||||
| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | ✔️ |
|
||||
| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | ✔️ |
|
||||
| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | ✔️ |
|
||||
| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | ✔️ |
|
||||
| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ |
|
||||
| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | ✔️ |
|
||||
| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ |
|
||||
| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | ✔️ |
|
||||
| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | ✔️ |
|
||||
| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | ✔️ |
|
||||
| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ |
|
||||
| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | ✔️ |
|
||||
| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | ✔️ |
|
||||
| legacy/[Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | ✔️ |
|
||||
| legacy/[MD5](https://datatracker.ietf.org/doc/html/rfc1321) | ✔️ |
|
||||
| legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | ✔️ |
|
||||
|
||||
#### High level API
|
||||
Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*.
|
||||
Included in these groups are six procedures.
|
||||
* `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally
|
||||
* `hash_bytes` - Hash a given byte slice and return the computed hash
|
||||
* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally
|
||||
* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash
|
||||
* `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it
|
||||
* `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true)
|
||||
|
||||
\* On some algorithms there is another part to the name, since they might offer control about additional parameters.
|
||||
For instance, `HAVAL` offers different sizes as well as three different round amounts.
|
||||
Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.hash_256_3(...)`.
|
||||
Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*.
|
||||
Included in these groups are six procedures.
|
||||
- `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally
|
||||
- `hash_bytes` - Hash a given byte slice and return the computed hash
|
||||
- `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally
|
||||
- `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash
|
||||
- `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it
|
||||
- `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true)
|
||||
|
||||
\* On some algorithms there is another part to the name, since they might offer control about additional parameters.
|
||||
For instance, `SHA-2` offers different sizes.
|
||||
Computing a 512-bit hash is therefore achieved by calling `sha2.hash_512(...)`.
|
||||
|
||||
#### Low level API
|
||||
|
||||
The above mentioned procedures internally call three procedures: `init`, `update` and `final`.
|
||||
You may also directly call them, if you wish.
|
||||
|
||||
#### Example
|
||||
|
||||
```odin
|
||||
package crypto_example
|
||||
|
||||
// Import the desired package
|
||||
import "core:crypto/md4"
|
||||
import "core:crypto/blake2b"
|
||||
|
||||
main :: proc() {
|
||||
input := "foo"
|
||||
|
||||
// Compute the hash, using the high level API
|
||||
computed_hash := md4.hash(input)
|
||||
computed_hash := blake2b.hash(input)
|
||||
|
||||
// Variant that takes a destination buffer, instead of returning the computed hash
|
||||
hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash
|
||||
md4.hash(input, hash[:])
|
||||
hash := make([]byte, sha2.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash
|
||||
blake2b.hash(input, hash[:])
|
||||
|
||||
// Compute the hash, using the low level API
|
||||
ctx: md4.Md4_Context
|
||||
computed_hash_low: [16]byte
|
||||
md4.init(&ctx)
|
||||
md4.update(&ctx, transmute([]byte)input)
|
||||
md4.final(&ctx, computed_hash_low[:])
|
||||
ctx: blake2b.Context
|
||||
computed_hash_low: [blake2b.DIGEST_SIZE]byte
|
||||
blake2b.init(&ctx)
|
||||
blake2b.update(&ctx, transmute([]byte)input)
|
||||
blake2b.final(&ctx, computed_hash_low[:])
|
||||
}
|
||||
```
|
||||
For example uses of all available algorithms, please see the tests within `tests/core/crypto`.
|
||||
|
||||
#### Thread safety
|
||||
The crypto package is not thread-safe at the moment. This may change in the future.
|
||||
## Implementation considerations
|
||||
|
||||
### Disclaimer
|
||||
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.
|
||||
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.
|
||||
- The crypto packages are not thread-safe.
|
||||
- Best-effort is make to mitigate timing side-channels on reasonable
|
||||
architectures. Architectures that are known to be unreasonable include
|
||||
but are not limited to i386, i486, and WebAssembly.
|
||||
- Some but not all of the packages attempt to santize sensitive data,
|
||||
however this is not done consistently through the library at the moment.
|
||||
As Thomas Pornin puts it "In general, such memory cleansing is a fool's
|
||||
quest."
|
||||
- All of these packages have not received independent third party review.
|
||||
|
||||
### ToDo
|
||||
* Ciphers (Symmetric, Asymmetric)
|
||||
* MACs (Message Authentication Code)
|
||||
* CSPRNGs (Cryptographically Secure PseudoRandom Number Generator)
|
||||
* KDFs (Key Derivation Function)
|
||||
* KEAs (Key Exchange Algorithm)
|
||||
## License
|
||||
|
||||
### License
|
||||
This library is made available under the BSD-3 license.
|
||||
@@ -10,12 +10,12 @@ package _blake2
|
||||
Implementation of the BLAKE2 hashing algorithm, as defined in <https://datatracker.ietf.org/doc/html/rfc7693> and <https://www.blake2.net/>
|
||||
*/
|
||||
|
||||
import "../util"
|
||||
import "core:encoding/endian"
|
||||
|
||||
BLAKE2S_BLOCK_SIZE :: 64
|
||||
BLAKE2S_SIZE :: 32
|
||||
BLAKE2B_BLOCK_SIZE :: 128
|
||||
BLAKE2B_SIZE :: 64
|
||||
BLAKE2S_BLOCK_SIZE :: 64
|
||||
BLAKE2S_SIZE :: 32
|
||||
BLAKE2B_BLOCK_SIZE :: 128
|
||||
BLAKE2B_SIZE :: 64
|
||||
|
||||
Blake2s_Context :: struct {
|
||||
h: [8]u32,
|
||||
@@ -28,7 +28,9 @@ Blake2s_Context :: struct {
|
||||
is_keyed: bool,
|
||||
size: byte,
|
||||
is_last_node: bool,
|
||||
cfg: Blake2_Config,
|
||||
cfg: Blake2_Config,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
Blake2b_Context :: struct {
|
||||
@@ -42,15 +44,19 @@ Blake2b_Context :: struct {
|
||||
is_keyed: bool,
|
||||
size: byte,
|
||||
is_last_node: bool,
|
||||
cfg: Blake2_Config,
|
||||
cfg: Blake2_Config,
|
||||
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
Blake2_Config :: struct {
|
||||
size: byte,
|
||||
key: []byte,
|
||||
salt: []byte,
|
||||
size: byte,
|
||||
key: []byte,
|
||||
salt: []byte,
|
||||
person: []byte,
|
||||
tree: union{Blake2_Tree},
|
||||
tree: union {
|
||||
Blake2_Tree,
|
||||
},
|
||||
}
|
||||
|
||||
Blake2_Tree :: struct {
|
||||
@@ -63,11 +69,13 @@ Blake2_Tree :: struct {
|
||||
is_last_node: bool,
|
||||
}
|
||||
|
||||
@(private)
|
||||
BLAKE2S_IV := [8]u32 {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
}
|
||||
|
||||
@(private)
|
||||
BLAKE2B_IV := [8]u64 {
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
@@ -78,8 +86,14 @@ BLAKE2B_IV := [8]u64 {
|
||||
init :: proc(ctx: ^$T) {
|
||||
when T == Blake2s_Context {
|
||||
block_size :: BLAKE2S_BLOCK_SIZE
|
||||
max_size :: BLAKE2S_SIZE
|
||||
} else when T == Blake2b_Context {
|
||||
block_size :: BLAKE2B_BLOCK_SIZE
|
||||
max_size :: BLAKE2B_SIZE
|
||||
}
|
||||
|
||||
if ctx.cfg.size > max_size {
|
||||
panic("blake2: requested output size exceeeds algorithm max")
|
||||
}
|
||||
|
||||
p := make([]byte, block_size)
|
||||
@@ -106,10 +120,10 @@ init :: proc(ctx: ^$T) {
|
||||
if ctx.cfg.tree != nil {
|
||||
p[2] = ctx.cfg.tree.(Blake2_Tree).fanout
|
||||
p[3] = ctx.cfg.tree.(Blake2_Tree).max_depth
|
||||
util.PUT_U32_LE(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size)
|
||||
endian.unchecked_put_u32le(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size)
|
||||
when T == Blake2s_Context {
|
||||
p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8)
|
||||
p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8)
|
||||
p[10] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 16)
|
||||
p[11] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 24)
|
||||
p[12] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 32)
|
||||
@@ -117,7 +131,7 @@ init :: proc(ctx: ^$T) {
|
||||
p[14] = ctx.cfg.tree.(Blake2_Tree).node_depth
|
||||
p[15] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size
|
||||
} else when T == Blake2b_Context {
|
||||
util.PUT_U64_LE(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
endian.unchecked_put_u64le(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset)
|
||||
p[16] = ctx.cfg.tree.(Blake2_Tree).node_depth
|
||||
p[17] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size
|
||||
}
|
||||
@@ -127,10 +141,10 @@ init :: proc(ctx: ^$T) {
|
||||
ctx.size = ctx.cfg.size
|
||||
for i := 0; i < 8; i += 1 {
|
||||
when T == Blake2s_Context {
|
||||
ctx.h[i] = BLAKE2S_IV[i] ~ util.U32_LE(p[i * 4:])
|
||||
ctx.h[i] = BLAKE2S_IV[i] ~ endian.unchecked_get_u32le(p[i * 4:])
|
||||
}
|
||||
when T == Blake2b_Context {
|
||||
ctx.h[i] = BLAKE2B_IV[i] ~ util.U64_LE(p[i * 8:])
|
||||
ctx.h[i] = BLAKE2B_IV[i] ~ endian.unchecked_get_u64le(p[i * 8:])
|
||||
}
|
||||
}
|
||||
if ctx.cfg.tree != nil && ctx.cfg.tree.(Blake2_Tree).is_last_node {
|
||||
@@ -142,13 +156,19 @@ init :: proc(ctx: ^$T) {
|
||||
ctx.is_keyed = true
|
||||
}
|
||||
copy(ctx.ih[:], ctx.h[:])
|
||||
copy(ctx.h[:], ctx.ih[:])
|
||||
copy(ctx.h[:], ctx.ih[:])
|
||||
if ctx.is_keyed {
|
||||
update(ctx, ctx.padded_key[:])
|
||||
}
|
||||
|
||||
ctx.nx = 0
|
||||
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
update :: proc(ctx: ^$T, p: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
p := p
|
||||
when T == Blake2s_Context {
|
||||
block_size :: BLAKE2S_BLOCK_SIZE
|
||||
@@ -174,15 +194,25 @@ update :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
ctx.nx += copy(ctx.x[ctx.nx:], p)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^$T, hash: []byte) {
|
||||
final :: proc(ctx: ^$T, hash: []byte) {
|
||||
assert(ctx.is_initialized)
|
||||
|
||||
when T == Blake2s_Context {
|
||||
if len(hash) < int(ctx.cfg.size) {
|
||||
panic("crypto/blake2s: invalid destination digest size")
|
||||
}
|
||||
blake2s_final(ctx, hash)
|
||||
}
|
||||
when T == Blake2b_Context {
|
||||
} else when T == Blake2b_Context {
|
||||
if len(hash) < int(ctx.cfg.size) {
|
||||
panic("crypto/blake2b: invalid destination digest size")
|
||||
}
|
||||
blake2b_final(ctx, hash)
|
||||
}
|
||||
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
|
||||
if ctx.is_keyed {
|
||||
for i := 0; i < len(ctx.padded_key); i += 1 {
|
||||
@@ -203,16 +233,14 @@ blake2s_final :: proc "contextless" (ctx: ^Blake2s_Context, hash: []byte) {
|
||||
|
||||
blocks(ctx, ctx.x[:])
|
||||
|
||||
j := 0
|
||||
for s, _ in ctx.h[:(ctx.size - 1) / 4 + 1] {
|
||||
hash[j + 0] = byte(s >> 0)
|
||||
hash[j + 1] = byte(s >> 8)
|
||||
hash[j + 2] = byte(s >> 16)
|
||||
hash[j + 3] = byte(s >> 24)
|
||||
j += 4
|
||||
dst: [BLAKE2S_SIZE]byte
|
||||
for i := 0; i < BLAKE2S_SIZE / 4; i += 1 {
|
||||
endian.unchecked_put_u32le(dst[i * 4:], ctx.h[i])
|
||||
}
|
||||
copy(hash, dst[:])
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) {
|
||||
if ctx.is_keyed {
|
||||
for i := 0; i < len(ctx.padded_key); i += 1 {
|
||||
@@ -229,56 +257,52 @@ blake2b_final :: proc "contextless" (ctx: ^Blake2b_Context, hash: []byte) {
|
||||
ctx.f[0] = 0xffffffffffffffff
|
||||
if ctx.is_last_node {
|
||||
ctx.f[1] = 0xffffffffffffffff
|
||||
}
|
||||
}
|
||||
|
||||
blocks(ctx, ctx.x[:])
|
||||
|
||||
j := 0
|
||||
for s, _ in ctx.h[:(ctx.size - 1) / 8 + 1] {
|
||||
hash[j + 0] = byte(s >> 0)
|
||||
hash[j + 1] = byte(s >> 8)
|
||||
hash[j + 2] = byte(s >> 16)
|
||||
hash[j + 3] = byte(s >> 24)
|
||||
hash[j + 4] = byte(s >> 32)
|
||||
hash[j + 5] = byte(s >> 40)
|
||||
hash[j + 6] = byte(s >> 48)
|
||||
hash[j + 7] = byte(s >> 56)
|
||||
j += 8
|
||||
dst: [BLAKE2B_SIZE]byte
|
||||
for i := 0; i < BLAKE2B_SIZE / 8; i += 1 {
|
||||
endian.unchecked_put_u64le(dst[i * 8:], ctx.h[i])
|
||||
}
|
||||
copy(hash, dst[:])
|
||||
}
|
||||
|
||||
@(private)
|
||||
blocks :: proc "contextless" (ctx: ^$T, p: []byte) {
|
||||
when T == Blake2s_Context {
|
||||
blake2s_blocks(ctx, p)
|
||||
}
|
||||
when T == Blake2b_Context {
|
||||
} else when T == Blake2b_Context {
|
||||
blake2b_blocks(ctx, p)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []byte) {
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 :=
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
p := p
|
||||
for len(p) >= BLAKE2S_BLOCK_SIZE {
|
||||
ctx.t[0] += BLAKE2S_BLOCK_SIZE
|
||||
if ctx.t[0] < BLAKE2S_BLOCK_SIZE {
|
||||
ctx.t[1] += 1
|
||||
}
|
||||
}
|
||||
v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7
|
||||
v8 := BLAKE2S_IV[0]
|
||||
v9 := BLAKE2S_IV[1]
|
||||
v8 := BLAKE2S_IV[0]
|
||||
v9 := BLAKE2S_IV[1]
|
||||
v10 := BLAKE2S_IV[2]
|
||||
v11 := BLAKE2S_IV[3]
|
||||
v12 := BLAKE2S_IV[4] ~ ctx.t[0]
|
||||
v13 := BLAKE2S_IV[5] ~ ctx.t[1]
|
||||
v14 := BLAKE2S_IV[6] ~ ctx.f[0]
|
||||
v15 := BLAKE2S_IV[7] ~ ctx.f[1]
|
||||
m: [16]u32
|
||||
j := 0
|
||||
|
||||
m: [16]u32 = ---
|
||||
for i := 0; i < 16; i += 1 {
|
||||
m[i] = u32(p[j]) | u32(p[j + 1]) << 8 | u32(p[j + 2]) << 16 | u32(p[j + 3]) << 24
|
||||
j += 4
|
||||
m[i] = endian.unchecked_get_u32le(p[i * 4:])
|
||||
}
|
||||
|
||||
// Round 1
|
||||
v0 += m[0]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -391,6 +415,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 2
|
||||
v0 += m[14]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -503,6 +529,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 3
|
||||
v0 += m[11]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -615,6 +643,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 4
|
||||
v0 += m[7]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -727,6 +757,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 5
|
||||
v0 += m[9]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -839,6 +871,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 6
|
||||
v0 += m[2]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -951,6 +985,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 7
|
||||
v0 += m[12]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1063,6 +1099,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 8
|
||||
v0 += m[13]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1175,6 +1213,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 9
|
||||
v0 += m[6]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1287,6 +1327,8 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
// Round 10
|
||||
v0 += m[10]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1399,6 +1441,7 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (32 - 7) | v5 >> 7
|
||||
|
||||
h0 ~= v0 ~ v8
|
||||
h1 ~= v1 ~ v9
|
||||
h2 ~= v2 ~ v10
|
||||
@@ -1407,19 +1450,23 @@ blake2s_blocks :: #force_inline proc "contextless" (ctx: ^Blake2s_Context, p: []
|
||||
h5 ~= v5 ~ v13
|
||||
h6 ~= v6 ~ v14
|
||||
h7 ~= v7 ~ v15
|
||||
|
||||
p = p[BLAKE2S_BLOCK_SIZE:]
|
||||
}
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] =
|
||||
h0, h1, h2, h3, h4, h5, h6, h7
|
||||
}
|
||||
|
||||
@(private)
|
||||
blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []byte) {
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 := ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
h0, h1, h2, h3, h4, h5, h6, h7 :=
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7]
|
||||
p := p
|
||||
for len(p) >= BLAKE2B_BLOCK_SIZE {
|
||||
ctx.t[0] += BLAKE2B_BLOCK_SIZE
|
||||
if ctx.t[0] < BLAKE2B_BLOCK_SIZE {
|
||||
ctx.t[1]+=1
|
||||
}
|
||||
ctx.t[1] += 1
|
||||
}
|
||||
v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7
|
||||
v8 := BLAKE2B_IV[0]
|
||||
v9 := BLAKE2B_IV[1]
|
||||
@@ -1429,13 +1476,13 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v13 := BLAKE2B_IV[5] ~ ctx.t[1]
|
||||
v14 := BLAKE2B_IV[6] ~ ctx.f[0]
|
||||
v15 := BLAKE2B_IV[7] ~ ctx.f[1]
|
||||
|
||||
m: [16]u64 = ---
|
||||
j := 0
|
||||
for i := 0; i < 16; i+=1 {
|
||||
m[i] = u64(p[j]) | u64(p[j + 1]) << 8 | u64(p[j + 2]) << 16 | u64(p[j + 3]) << 24 |
|
||||
u64(p[j + 4]) << 32 | u64(p[j + 5]) << 40 | u64(p[j + 6]) << 48 | u64(p[j + 7]) << 56
|
||||
j += 8
|
||||
for i := 0; i < 16; i += 1 {
|
||||
m[i] = endian.unchecked_get_u64le(p[i * 8:])
|
||||
}
|
||||
|
||||
// Round 1
|
||||
v0 += m[0]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1548,6 +1595,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 2
|
||||
v0 += m[14]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1660,6 +1709,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 3
|
||||
v0 += m[11]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1772,6 +1823,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 4
|
||||
v0 += m[7]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1884,6 +1937,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 5
|
||||
v0 += m[9]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -1996,6 +2051,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 6
|
||||
v0 += m[2]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2108,6 +2165,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 7
|
||||
v0 += m[12]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2220,6 +2279,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 8
|
||||
v0 += m[13]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2332,6 +2393,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 9
|
||||
v0 += m[6]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2444,6 +2507,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 10
|
||||
v0 += m[10]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2556,6 +2621,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 11
|
||||
v0 += m[0]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2668,6 +2735,8 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
// Round 12
|
||||
v0 += m[14]
|
||||
v0 += v4
|
||||
v12 ~= v0
|
||||
@@ -2780,6 +2849,7 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
v10 += v15
|
||||
v5 ~= v10
|
||||
v5 = v5 << (64 - 63) | v5 >> 63
|
||||
|
||||
h0 ~= v0 ~ v8
|
||||
h1 ~= v1 ~ v9
|
||||
h2 ~= v2 ~ v10
|
||||
@@ -2788,7 +2858,9 @@ blake2b_blocks :: #force_inline proc "contextless" (ctx: ^Blake2b_Context, p: []
|
||||
h5 ~= v5 ~ v13
|
||||
h6 ~= v6 ~ v14
|
||||
h7 ~= v7 ~ v15
|
||||
|
||||
p = p[BLAKE2B_BLOCK_SIZE:]
|
||||
}
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
|
||||
}
|
||||
ctx.h[0], ctx.h[1], ctx.h[2], ctx.h[3], ctx.h[4], ctx.h[5], ctx.h[6], ctx.h[7] =
|
||||
h0, h1, h2, h3, h4, h5, h6, h7
|
||||
}
|
||||
@@ -9,14 +9,16 @@ package fiat
|
||||
u1 :: distinct u8
|
||||
i1 :: distinct i8
|
||||
|
||||
cmovznz_u64 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
|
||||
@(optimization_mode="none")
|
||||
cmovznz_u64 :: proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
|
||||
x1 := (u64(arg1) * 0xffffffffffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
out1 = x2
|
||||
return
|
||||
}
|
||||
|
||||
cmovznz_u32 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
|
||||
@(optimization_mode="none")
|
||||
cmovznz_u32 :: proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
|
||||
x1 := (u32(arg1) * 0xffffffff)
|
||||
x2 := ((x1 & arg3) | ((~x1) & arg2))
|
||||
out1 = x2
|
||||
|
||||
@@ -305,7 +305,8 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_assign :: #force_no_inline proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) {
|
||||
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
|
||||
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
|
||||
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
|
||||
@@ -596,7 +597,8 @@ fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
out1[4] = x5
|
||||
}
|
||||
|
||||
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
|
||||
mask := -u64(arg1)
|
||||
x := (out1[0] ~ out2[0]) & mask
|
||||
x1, y1 := out1[0] ~ x, out2[0] ~ x
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package field_poly1305
|
||||
|
||||
import "core:crypto/util"
|
||||
import "core:encoding/endian"
|
||||
import "core:mem"
|
||||
|
||||
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element {
|
||||
@@ -11,7 +11,7 @@ fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element)
|
||||
return transmute(^Tight_Field_Element)(arg1)
|
||||
}
|
||||
|
||||
fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) {
|
||||
fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte) {
|
||||
// fiat-crypto's deserialization routine effectively processes a
|
||||
// single byte at a time, and wants 256-bits of input for a value
|
||||
// that will be 128-bits or 129-bits.
|
||||
@@ -22,42 +22,29 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
|
||||
|
||||
assert(len(arg1) == 16)
|
||||
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
// While it may be unwise to do deserialization here on our
|
||||
// own when fiat-crypto provides equivalent functionality,
|
||||
// doing it this way provides a little under 3x performance
|
||||
// improvement when optimization is enabled.
|
||||
src_p := transmute(^[2]u64)(&arg1[0])
|
||||
lo := src_p[0]
|
||||
hi := src_p[1]
|
||||
// While it may be unwise to do deserialization here on our
|
||||
// own when fiat-crypto provides equivalent functionality,
|
||||
// doing it this way provides a little under 3x performance
|
||||
// improvement when optimization is enabled.
|
||||
lo := endian.unchecked_get_u64le(arg1[0:])
|
||||
hi := endian.unchecked_get_u64le(arg1[8:])
|
||||
|
||||
// This is inspired by poly1305-donna, though adjustments were
|
||||
// made since a Tight_Field_Element's limbs are 44-bits, 43-bits,
|
||||
// and 43-bits wide.
|
||||
//
|
||||
// Note: This could be transplated into fe_from_u64s, but that
|
||||
// code is called once per MAC, and is non-criticial path.
|
||||
hibit := u64(arg2) << 41 // arg2 << 128
|
||||
out1[0] = lo & 0xfffffffffff
|
||||
out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff
|
||||
out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit
|
||||
} else {
|
||||
tmp: [32]byte
|
||||
copy_slice(tmp[0:16], arg1[:])
|
||||
tmp[16] = arg2
|
||||
|
||||
_fe_from_bytes(out1, &tmp)
|
||||
if sanitize {
|
||||
// This is used to deserialize `s` which is confidential.
|
||||
mem.zero_explicit(&tmp, size_of(tmp))
|
||||
}
|
||||
}
|
||||
// This is inspired by poly1305-donna, though adjustments were
|
||||
// made since a Tight_Field_Element's limbs are 44-bits, 43-bits,
|
||||
// and 43-bits wide.
|
||||
//
|
||||
// Note: This could be transplated into fe_from_u64s, but that
|
||||
// code is called once per MAC, and is non-criticial path.
|
||||
hibit := u64(arg2) << 41 // arg2 << 128
|
||||
out1[0] = lo & 0xfffffffffff
|
||||
out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff
|
||||
out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit
|
||||
}
|
||||
|
||||
fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) {
|
||||
tmp: [32]byte
|
||||
util.PUT_U64_LE(tmp[0:8], lo)
|
||||
util.PUT_U64_LE(tmp[8:16], hi)
|
||||
endian.unchecked_put_u64le(tmp[0:], lo)
|
||||
endian.unchecked_put_u64le(tmp[8:], hi)
|
||||
|
||||
_fe_from_bytes(out1, &tmp)
|
||||
|
||||
|
||||
@@ -201,7 +201,8 @@ fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Ele
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_assign :: #force_no_inline proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) {
|
||||
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
|
||||
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
|
||||
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
|
||||
@@ -342,7 +343,8 @@ fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
|
||||
out1[2] = x3
|
||||
}
|
||||
|
||||
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) {
|
||||
@(optimization_mode="none")
|
||||
fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) {
|
||||
mask := -u64(arg1)
|
||||
x := (out1[0] ~ out2[0]) & mask
|
||||
x1, y1 := out1[0] ~ x, out2[0] ~ x
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
package _sha3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Keccak hashing algorithm, standardized as SHA3 in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>
|
||||
To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding.
|
||||
*/
|
||||
|
||||
import "../util"
|
||||
|
||||
ROUNDS :: 24
|
||||
|
||||
Sha3_Context :: struct {
|
||||
st: struct #raw_union {
|
||||
b: [200]u8,
|
||||
q: [25]u64,
|
||||
},
|
||||
pt: int,
|
||||
rsiz: int,
|
||||
mdlen: int,
|
||||
is_keccak: bool,
|
||||
}
|
||||
|
||||
keccakf :: proc "contextless" (st: ^[25]u64) {
|
||||
keccakf_rndc := [?]u64 {
|
||||
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
|
||||
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
|
||||
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
|
||||
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
||||
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
||||
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
|
||||
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
||||
0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
|
||||
}
|
||||
|
||||
keccakf_rotc := [?]i32 {
|
||||
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
|
||||
}
|
||||
|
||||
keccakf_piln := [?]i32 {
|
||||
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
|
||||
}
|
||||
|
||||
i, j, r: i32 = ---, ---, ---
|
||||
t: u64 = ---
|
||||
bc: [5]u64 = ---
|
||||
|
||||
when ODIN_ENDIAN != .Little {
|
||||
v: uintptr = ---
|
||||
for i = 0; i < 25; i += 1 {
|
||||
v := uintptr(&st[i])
|
||||
st[i] = u64((^u8)(v + 0)^ << 0) | u64((^u8)(v + 1)^ << 8) |
|
||||
u64((^u8)(v + 2)^ << 16) | u64((^u8)(v + 3)^ << 24) |
|
||||
u64((^u8)(v + 4)^ << 32) | u64((^u8)(v + 5)^ << 40) |
|
||||
u64((^u8)(v + 6)^ << 48) | u64((^u8)(v + 7)^ << 56)
|
||||
}
|
||||
}
|
||||
|
||||
for r = 0; r < ROUNDS; r += 1 {
|
||||
// theta
|
||||
for i = 0; i < 5; i += 1 {
|
||||
bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20]
|
||||
}
|
||||
|
||||
for i = 0; i < 5; i += 1 {
|
||||
t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1)
|
||||
for j = 0; j < 25; j += 5 {
|
||||
st[j + i] ~= t
|
||||
}
|
||||
}
|
||||
|
||||
// rho pi
|
||||
t = st[1]
|
||||
for i = 0; i < 24; i += 1 {
|
||||
j = keccakf_piln[i]
|
||||
bc[0] = st[j]
|
||||
st[j] = util.ROTL64(t, u64(keccakf_rotc[i]))
|
||||
t = bc[0]
|
||||
}
|
||||
|
||||
// chi
|
||||
for j = 0; j < 25; j += 5 {
|
||||
for i = 0; i < 5; i += 1 {
|
||||
bc[i] = st[j + i]
|
||||
}
|
||||
for i = 0; i < 5; i += 1 {
|
||||
st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5]
|
||||
}
|
||||
}
|
||||
|
||||
st[0] ~= keccakf_rndc[r]
|
||||
}
|
||||
|
||||
when ODIN_ENDIAN != .Little {
|
||||
for i = 0; i < 25; i += 1 {
|
||||
v = uintptr(&st[i])
|
||||
t = st[i]
|
||||
(^u8)(v + 0)^ = (t >> 0) & 0xff
|
||||
(^u8)(v + 1)^ = (t >> 8) & 0xff
|
||||
(^u8)(v + 2)^ = (t >> 16) & 0xff
|
||||
(^u8)(v + 3)^ = (t >> 24) & 0xff
|
||||
(^u8)(v + 4)^ = (t >> 32) & 0xff
|
||||
(^u8)(v + 5)^ = (t >> 40) & 0xff
|
||||
(^u8)(v + 6)^ = (t >> 48) & 0xff
|
||||
(^u8)(v + 7)^ = (t >> 56) & 0xff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init :: proc "contextless" (c: ^Sha3_Context) {
|
||||
for i := 0; i < 25; i += 1 {
|
||||
c.st.q[i] = 0
|
||||
}
|
||||
c.rsiz = 200 - 2 * c.mdlen
|
||||
}
|
||||
|
||||
update :: proc "contextless" (c: ^Sha3_Context, data: []byte) {
|
||||
j := c.pt
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
c.st.b[j] ~= data[i]
|
||||
j += 1
|
||||
if j >= c.rsiz {
|
||||
keccakf(&c.st.q)
|
||||
j = 0
|
||||
}
|
||||
}
|
||||
c.pt = j
|
||||
}
|
||||
|
||||
final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
|
||||
if c.is_keccak {
|
||||
c.st.b[c.pt] ~= 0x01
|
||||
} else {
|
||||
c.st.b[c.pt] ~= 0x06
|
||||
}
|
||||
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
for i := 0; i < c.mdlen; i += 1 {
|
||||
hash[i] = c.st.b[i]
|
||||
}
|
||||
}
|
||||
|
||||
shake_xof :: proc "contextless" (c: ^Sha3_Context) {
|
||||
c.st.b[c.pt] ~= 0x1F
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
c.pt = 0
|
||||
}
|
||||
|
||||
shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
|
||||
j := c.pt
|
||||
for i := 0; i < len(hash); i += 1 {
|
||||
if j >= c.rsiz {
|
||||
keccakf(&c.st.q)
|
||||
j = 0
|
||||
}
|
||||
hash[i] = c.st.b[j]
|
||||
j += 1
|
||||
}
|
||||
c.pt = j
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package _sha3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Keccak hashing algorithm, standardized as SHA3 in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>
|
||||
To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding.
|
||||
*/
|
||||
|
||||
import "core:math/bits"
|
||||
|
||||
ROUNDS :: 24
|
||||
|
||||
Sha3_Context :: struct {
|
||||
st: struct #raw_union {
|
||||
b: [200]u8,
|
||||
q: [25]u64,
|
||||
},
|
||||
pt: int,
|
||||
rsiz: int,
|
||||
mdlen: int,
|
||||
is_keccak: bool,
|
||||
|
||||
is_initialized: bool,
|
||||
is_finalized: bool, // For SHAKE (unlimited squeeze is allowed)
|
||||
}
|
||||
|
||||
keccakf :: proc "contextless" (st: ^[25]u64) {
|
||||
keccakf_rndc := [?]u64 {
|
||||
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
|
||||
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
|
||||
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
|
||||
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
||||
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
||||
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
|
||||
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
||||
0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
|
||||
}
|
||||
|
||||
keccakf_rotc := [?]int {
|
||||
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
|
||||
}
|
||||
|
||||
keccakf_piln := [?]i32 {
|
||||
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
|
||||
}
|
||||
|
||||
i, j, r: i32 = ---, ---, ---
|
||||
t: u64 = ---
|
||||
bc: [5]u64 = ---
|
||||
|
||||
when ODIN_ENDIAN != .Little {
|
||||
for i = 0; i < 25; i += 1 {
|
||||
st[i] = bits.byte_swap(st[i])
|
||||
}
|
||||
}
|
||||
|
||||
for r = 0; r < ROUNDS; r += 1 {
|
||||
// theta
|
||||
for i = 0; i < 5; i += 1 {
|
||||
bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20]
|
||||
}
|
||||
|
||||
for i = 0; i < 5; i += 1 {
|
||||
t = bc[(i + 4) % 5] ~ bits.rotate_left64(bc[(i + 1) % 5], 1)
|
||||
for j = 0; j < 25; j += 5 {
|
||||
st[j + i] ~= t
|
||||
}
|
||||
}
|
||||
|
||||
// rho pi
|
||||
t = st[1]
|
||||
for i = 0; i < 24; i += 1 {
|
||||
j = keccakf_piln[i]
|
||||
bc[0] = st[j]
|
||||
st[j] = bits.rotate_left64(t, keccakf_rotc[i])
|
||||
t = bc[0]
|
||||
}
|
||||
|
||||
// chi
|
||||
for j = 0; j < 25; j += 5 {
|
||||
for i = 0; i < 5; i += 1 {
|
||||
bc[i] = st[j + i]
|
||||
}
|
||||
for i = 0; i < 5; i += 1 {
|
||||
st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5]
|
||||
}
|
||||
}
|
||||
|
||||
st[0] ~= keccakf_rndc[r]
|
||||
}
|
||||
|
||||
when ODIN_ENDIAN != .Little {
|
||||
for i = 0; i < 25; i += 1 {
|
||||
st[i] = bits.byte_swap(st[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init :: proc(c: ^Sha3_Context) {
|
||||
for i := 0; i < 25; i += 1 {
|
||||
c.st.q[i] = 0
|
||||
}
|
||||
c.rsiz = 200 - 2 * c.mdlen
|
||||
c.pt = 0
|
||||
|
||||
c.is_initialized = true
|
||||
c.is_finalized = false
|
||||
}
|
||||
|
||||
update :: proc(c: ^Sha3_Context, data: []byte) {
|
||||
assert(c.is_initialized)
|
||||
assert(!c.is_finalized)
|
||||
|
||||
j := c.pt
|
||||
for i := 0; i < len(data); i += 1 {
|
||||
c.st.b[j] ~= data[i]
|
||||
j += 1
|
||||
if j >= c.rsiz {
|
||||
keccakf(&c.st.q)
|
||||
j = 0
|
||||
}
|
||||
}
|
||||
c.pt = j
|
||||
}
|
||||
|
||||
final :: proc(c: ^Sha3_Context, hash: []byte) {
|
||||
assert(c.is_initialized)
|
||||
|
||||
if len(hash) < c.mdlen {
|
||||
if c.is_keccak {
|
||||
panic("crypto/keccac: invalid destination digest size")
|
||||
}
|
||||
panic("crypto/sha3: invalid destination digest size")
|
||||
}
|
||||
if c.is_keccak {
|
||||
c.st.b[c.pt] ~= 0x01
|
||||
} else {
|
||||
c.st.b[c.pt] ~= 0x06
|
||||
}
|
||||
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
for i := 0; i < c.mdlen; i += 1 {
|
||||
hash[i] = c.st.b[i]
|
||||
}
|
||||
|
||||
c.is_initialized = false // No more absorb, no more squeeze.
|
||||
}
|
||||
|
||||
shake_xof :: proc(c: ^Sha3_Context) {
|
||||
assert(c.is_initialized)
|
||||
assert(!c.is_finalized)
|
||||
|
||||
c.st.b[c.pt] ~= 0x1F
|
||||
c.st.b[c.rsiz - 1] ~= 0x80
|
||||
keccakf(&c.st.q)
|
||||
c.pt = 0
|
||||
|
||||
c.is_finalized = true // No more absorb, unlimited squeeze.
|
||||
}
|
||||
|
||||
shake_out :: proc(c: ^Sha3_Context, hash: []byte) {
|
||||
assert(c.is_initialized)
|
||||
assert(c.is_finalized)
|
||||
|
||||
j := c.pt
|
||||
for i := 0; i < len(hash); i += 1 {
|
||||
if j >= c.rsiz {
|
||||
keccakf(&c.st.q)
|
||||
j = 0
|
||||
}
|
||||
hash[i] = c.st.b[j]
|
||||
j += 1
|
||||
}
|
||||
c.pt = j
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
package _tiger
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the Tiger hashing algorithm, as defined in <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
|
||||
*/
|
||||
|
||||
import "../util"
|
||||
|
||||
T1 := [?]u64 {
|
||||
0x02aab17cf7e90c5e, 0xac424b03e243a8ec, 0x72cd5be30dd5fcd3, 0x6d019b93f6f97f3a,
|
||||
0xcd9978ffd21f9193, 0x7573a1c9708029e2, 0xb164326b922a83c3, 0x46883eee04915870,
|
||||
0xeaace3057103ece6, 0xc54169b808a3535c, 0x4ce754918ddec47c, 0x0aa2f4dfdc0df40c,
|
||||
0x10b76f18a74dbefa, 0xc6ccb6235ad1ab6a, 0x13726121572fe2ff, 0x1a488c6f199d921e,
|
||||
0x4bc9f9f4da0007ca, 0x26f5e6f6e85241c7, 0x859079dbea5947b6, 0x4f1885c5c99e8c92,
|
||||
0xd78e761ea96f864b, 0x8e36428c52b5c17d, 0x69cf6827373063c1, 0xb607c93d9bb4c56e,
|
||||
0x7d820e760e76b5ea, 0x645c9cc6f07fdc42, 0xbf38a078243342e0, 0x5f6b343c9d2e7d04,
|
||||
0xf2c28aeb600b0ec6, 0x6c0ed85f7254bcac, 0x71592281a4db4fe5, 0x1967fa69ce0fed9f,
|
||||
0xfd5293f8b96545db, 0xc879e9d7f2a7600b, 0x860248920193194e, 0xa4f9533b2d9cc0b3,
|
||||
0x9053836c15957613, 0xdb6dcf8afc357bf1, 0x18beea7a7a370f57, 0x037117ca50b99066,
|
||||
0x6ab30a9774424a35, 0xf4e92f02e325249b, 0x7739db07061ccae1, 0xd8f3b49ceca42a05,
|
||||
0xbd56be3f51382f73, 0x45faed5843b0bb28, 0x1c813d5c11bf1f83, 0x8af0e4b6d75fa169,
|
||||
0x33ee18a487ad9999, 0x3c26e8eab1c94410, 0xb510102bc0a822f9, 0x141eef310ce6123b,
|
||||
0xfc65b90059ddb154, 0xe0158640c5e0e607, 0x884e079826c3a3cf, 0x930d0d9523c535fd,
|
||||
0x35638d754e9a2b00, 0x4085fccf40469dd5, 0xc4b17ad28be23a4c, 0xcab2f0fc6a3e6a2e,
|
||||
0x2860971a6b943fcd, 0x3dde6ee212e30446, 0x6222f32ae01765ae, 0x5d550bb5478308fe,
|
||||
0xa9efa98da0eda22a, 0xc351a71686c40da7, 0x1105586d9c867c84, 0xdcffee85fda22853,
|
||||
0xccfbd0262c5eef76, 0xbaf294cb8990d201, 0xe69464f52afad975, 0x94b013afdf133e14,
|
||||
0x06a7d1a32823c958, 0x6f95fe5130f61119, 0xd92ab34e462c06c0, 0xed7bde33887c71d2,
|
||||
0x79746d6e6518393e, 0x5ba419385d713329, 0x7c1ba6b948a97564, 0x31987c197bfdac67,
|
||||
0xde6c23c44b053d02, 0x581c49fed002d64d, 0xdd474d6338261571, 0xaa4546c3e473d062,
|
||||
0x928fce349455f860, 0x48161bbacaab94d9, 0x63912430770e6f68, 0x6ec8a5e602c6641c,
|
||||
0x87282515337ddd2b, 0x2cda6b42034b701b, 0xb03d37c181cb096d, 0xe108438266c71c6f,
|
||||
0x2b3180c7eb51b255, 0xdf92b82f96c08bbc, 0x5c68c8c0a632f3ba, 0x5504cc861c3d0556,
|
||||
0xabbfa4e55fb26b8f, 0x41848b0ab3baceb4, 0xb334a273aa445d32, 0xbca696f0a85ad881,
|
||||
0x24f6ec65b528d56c, 0x0ce1512e90f4524a, 0x4e9dd79d5506d35a, 0x258905fac6ce9779,
|
||||
0x2019295b3e109b33, 0xf8a9478b73a054cc, 0x2924f2f934417eb0, 0x3993357d536d1bc4,
|
||||
0x38a81ac21db6ff8b, 0x47c4fbf17d6016bf, 0x1e0faadd7667e3f5, 0x7abcff62938beb96,
|
||||
0xa78dad948fc179c9, 0x8f1f98b72911e50d, 0x61e48eae27121a91, 0x4d62f7ad31859808,
|
||||
0xeceba345ef5ceaeb, 0xf5ceb25ebc9684ce, 0xf633e20cb7f76221, 0xa32cdf06ab8293e4,
|
||||
0x985a202ca5ee2ca4, 0xcf0b8447cc8a8fb1, 0x9f765244979859a3, 0xa8d516b1a1240017,
|
||||
0x0bd7ba3ebb5dc726, 0xe54bca55b86adb39, 0x1d7a3afd6c478063, 0x519ec608e7669edd,
|
||||
0x0e5715a2d149aa23, 0x177d4571848ff194, 0xeeb55f3241014c22, 0x0f5e5ca13a6e2ec2,
|
||||
0x8029927b75f5c361, 0xad139fabc3d6e436, 0x0d5df1a94ccf402f, 0x3e8bd948bea5dfc8,
|
||||
0xa5a0d357bd3ff77e, 0xa2d12e251f74f645, 0x66fd9e525e81a082, 0x2e0c90ce7f687a49,
|
||||
0xc2e8bcbeba973bc5, 0x000001bce509745f, 0x423777bbe6dab3d6, 0xd1661c7eaef06eb5,
|
||||
0xa1781f354daacfd8, 0x2d11284a2b16affc, 0xf1fc4f67fa891d1f, 0x73ecc25dcb920ada,
|
||||
0xae610c22c2a12651, 0x96e0a810d356b78a, 0x5a9a381f2fe7870f, 0xd5ad62ede94e5530,
|
||||
0xd225e5e8368d1427, 0x65977b70c7af4631, 0x99f889b2de39d74f, 0x233f30bf54e1d143,
|
||||
0x9a9675d3d9a63c97, 0x5470554ff334f9a8, 0x166acb744a4f5688, 0x70c74caab2e4aead,
|
||||
0xf0d091646f294d12, 0x57b82a89684031d1, 0xefd95a5a61be0b6b, 0x2fbd12e969f2f29a,
|
||||
0x9bd37013feff9fe8, 0x3f9b0404d6085a06, 0x4940c1f3166cfe15, 0x09542c4dcdf3defb,
|
||||
0xb4c5218385cd5ce3, 0xc935b7dc4462a641, 0x3417f8a68ed3b63f, 0xb80959295b215b40,
|
||||
0xf99cdaef3b8c8572, 0x018c0614f8fcb95d, 0x1b14accd1a3acdf3, 0x84d471f200bb732d,
|
||||
0xc1a3110e95e8da16, 0x430a7220bf1a82b8, 0xb77e090d39df210e, 0x5ef4bd9f3cd05e9d,
|
||||
0x9d4ff6da7e57a444, 0xda1d60e183d4a5f8, 0xb287c38417998e47, 0xfe3edc121bb31886,
|
||||
0xc7fe3ccc980ccbef, 0xe46fb590189bfd03, 0x3732fd469a4c57dc, 0x7ef700a07cf1ad65,
|
||||
0x59c64468a31d8859, 0x762fb0b4d45b61f6, 0x155baed099047718, 0x68755e4c3d50baa6,
|
||||
0xe9214e7f22d8b4df, 0x2addbf532eac95f4, 0x32ae3909b4bd0109, 0x834df537b08e3450,
|
||||
0xfa209da84220728d, 0x9e691d9b9efe23f7, 0x0446d288c4ae8d7f, 0x7b4cc524e169785b,
|
||||
0x21d87f0135ca1385, 0xcebb400f137b8aa5, 0x272e2b66580796be, 0x3612264125c2b0de,
|
||||
0x057702bdad1efbb2, 0xd4babb8eacf84be9, 0x91583139641bc67b, 0x8bdc2de08036e024,
|
||||
0x603c8156f49f68ed, 0xf7d236f7dbef5111, 0x9727c4598ad21e80, 0xa08a0896670a5fd7,
|
||||
0xcb4a8f4309eba9cb, 0x81af564b0f7036a1, 0xc0b99aa778199abd, 0x959f1ec83fc8e952,
|
||||
0x8c505077794a81b9, 0x3acaaf8f056338f0, 0x07b43f50627a6778, 0x4a44ab49f5eccc77,
|
||||
0x3bc3d6e4b679ee98, 0x9cc0d4d1cf14108c, 0x4406c00b206bc8a0, 0x82a18854c8d72d89,
|
||||
0x67e366b35c3c432c, 0xb923dd61102b37f2, 0x56ab2779d884271d, 0xbe83e1b0ff1525af,
|
||||
0xfb7c65d4217e49a9, 0x6bdbe0e76d48e7d4, 0x08df828745d9179e, 0x22ea6a9add53bd34,
|
||||
0xe36e141c5622200a, 0x7f805d1b8cb750ee, 0xafe5c7a59f58e837, 0xe27f996a4fb1c23c,
|
||||
0xd3867dfb0775f0d0, 0xd0e673de6e88891a, 0x123aeb9eafb86c25, 0x30f1d5d5c145b895,
|
||||
0xbb434a2dee7269e7, 0x78cb67ecf931fa38, 0xf33b0372323bbf9c, 0x52d66336fb279c74,
|
||||
0x505f33ac0afb4eaa, 0xe8a5cd99a2cce187, 0x534974801e2d30bb, 0x8d2d5711d5876d90,
|
||||
0x1f1a412891bc038e, 0xd6e2e71d82e56648, 0x74036c3a497732b7, 0x89b67ed96361f5ab,
|
||||
0xffed95d8f1ea02a2, 0xe72b3bd61464d43d, 0xa6300f170bdc4820, 0xebc18760ed78a77a,
|
||||
}
|
||||
|
||||
T2 := [?]u64 {
|
||||
0xe6a6be5a05a12138, 0xb5a122a5b4f87c98, 0x563c6089140b6990, 0x4c46cb2e391f5dd5,
|
||||
0xd932addbc9b79434, 0x08ea70e42015aff5, 0xd765a6673e478cf1, 0xc4fb757eab278d99,
|
||||
0xdf11c6862d6e0692, 0xddeb84f10d7f3b16, 0x6f2ef604a665ea04, 0x4a8e0f0ff0e0dfb3,
|
||||
0xa5edeef83dbcba51, 0xfc4f0a2a0ea4371e, 0xe83e1da85cb38429, 0xdc8ff882ba1b1ce2,
|
||||
0xcd45505e8353e80d, 0x18d19a00d4db0717, 0x34a0cfeda5f38101, 0x0be77e518887caf2,
|
||||
0x1e341438b3c45136, 0xe05797f49089ccf9, 0xffd23f9df2591d14, 0x543dda228595c5cd,
|
||||
0x661f81fd99052a33, 0x8736e641db0f7b76, 0x15227725418e5307, 0xe25f7f46162eb2fa,
|
||||
0x48a8b2126c13d9fe, 0xafdc541792e76eea, 0x03d912bfc6d1898f, 0x31b1aafa1b83f51b,
|
||||
0xf1ac2796e42ab7d9, 0x40a3a7d7fcd2ebac, 0x1056136d0afbbcc5, 0x7889e1dd9a6d0c85,
|
||||
0xd33525782a7974aa, 0xa7e25d09078ac09b, 0xbd4138b3eac6edd0, 0x920abfbe71eb9e70,
|
||||
0xa2a5d0f54fc2625c, 0xc054e36b0b1290a3, 0xf6dd59ff62fe932b, 0x3537354511a8ac7d,
|
||||
0xca845e9172fadcd4, 0x84f82b60329d20dc, 0x79c62ce1cd672f18, 0x8b09a2add124642c,
|
||||
0xd0c1e96a19d9e726, 0x5a786a9b4ba9500c, 0x0e020336634c43f3, 0xc17b474aeb66d822,
|
||||
0x6a731ae3ec9baac2, 0x8226667ae0840258, 0x67d4567691caeca5, 0x1d94155c4875adb5,
|
||||
0x6d00fd985b813fdf, 0x51286efcb774cd06, 0x5e8834471fa744af, 0xf72ca0aee761ae2e,
|
||||
0xbe40e4cdaee8e09a, 0xe9970bbb5118f665, 0x726e4beb33df1964, 0x703b000729199762,
|
||||
0x4631d816f5ef30a7, 0xb880b5b51504a6be, 0x641793c37ed84b6c, 0x7b21ed77f6e97d96,
|
||||
0x776306312ef96b73, 0xae528948e86ff3f4, 0x53dbd7f286a3f8f8, 0x16cadce74cfc1063,
|
||||
0x005c19bdfa52c6dd, 0x68868f5d64d46ad3, 0x3a9d512ccf1e186a, 0x367e62c2385660ae,
|
||||
0xe359e7ea77dcb1d7, 0x526c0773749abe6e, 0x735ae5f9d09f734b, 0x493fc7cc8a558ba8,
|
||||
0xb0b9c1533041ab45, 0x321958ba470a59bd, 0x852db00b5f46c393, 0x91209b2bd336b0e5,
|
||||
0x6e604f7d659ef19f, 0xb99a8ae2782ccb24, 0xccf52ab6c814c4c7, 0x4727d9afbe11727b,
|
||||
0x7e950d0c0121b34d, 0x756f435670ad471f, 0xf5add442615a6849, 0x4e87e09980b9957a,
|
||||
0x2acfa1df50aee355, 0xd898263afd2fd556, 0xc8f4924dd80c8fd6, 0xcf99ca3d754a173a,
|
||||
0xfe477bacaf91bf3c, 0xed5371f6d690c12d, 0x831a5c285e687094, 0xc5d3c90a3708a0a4,
|
||||
0x0f7f903717d06580, 0x19f9bb13b8fdf27f, 0xb1bd6f1b4d502843, 0x1c761ba38fff4012,
|
||||
0x0d1530c4e2e21f3b, 0x8943ce69a7372c8a, 0xe5184e11feb5ce66, 0x618bdb80bd736621,
|
||||
0x7d29bad68b574d0b, 0x81bb613e25e6fe5b, 0x071c9c10bc07913f, 0xc7beeb7909ac2d97,
|
||||
0xc3e58d353bc5d757, 0xeb017892f38f61e8, 0xd4effb9c9b1cc21a, 0x99727d26f494f7ab,
|
||||
0xa3e063a2956b3e03, 0x9d4a8b9a4aa09c30, 0x3f6ab7d500090fb4, 0x9cc0f2a057268ac0,
|
||||
0x3dee9d2dedbf42d1, 0x330f49c87960a972, 0xc6b2720287421b41, 0x0ac59ec07c00369c,
|
||||
0xef4eac49cb353425, 0xf450244eef0129d8, 0x8acc46e5caf4deb6, 0x2ffeab63989263f7,
|
||||
0x8f7cb9fe5d7a4578, 0x5bd8f7644e634635, 0x427a7315bf2dc900, 0x17d0c4aa2125261c,
|
||||
0x3992486c93518e50, 0xb4cbfee0a2d7d4c3, 0x7c75d6202c5ddd8d, 0xdbc295d8e35b6c61,
|
||||
0x60b369d302032b19, 0xce42685fdce44132, 0x06f3ddb9ddf65610, 0x8ea4d21db5e148f0,
|
||||
0x20b0fce62fcd496f, 0x2c1b912358b0ee31, 0xb28317b818f5a308, 0xa89c1e189ca6d2cf,
|
||||
0x0c6b18576aaadbc8, 0xb65deaa91299fae3, 0xfb2b794b7f1027e7, 0x04e4317f443b5beb,
|
||||
0x4b852d325939d0a6, 0xd5ae6beefb207ffc, 0x309682b281c7d374, 0xbae309a194c3b475,
|
||||
0x8cc3f97b13b49f05, 0x98a9422ff8293967, 0x244b16b01076ff7c, 0xf8bf571c663d67ee,
|
||||
0x1f0d6758eee30da1, 0xc9b611d97adeb9b7, 0xb7afd5887b6c57a2, 0x6290ae846b984fe1,
|
||||
0x94df4cdeacc1a5fd, 0x058a5bd1c5483aff, 0x63166cc142ba3c37, 0x8db8526eb2f76f40,
|
||||
0xe10880036f0d6d4e, 0x9e0523c9971d311d, 0x45ec2824cc7cd691, 0x575b8359e62382c9,
|
||||
0xfa9e400dc4889995, 0xd1823ecb45721568, 0xdafd983b8206082f, 0xaa7d29082386a8cb,
|
||||
0x269fcd4403b87588, 0x1b91f5f728bdd1e0, 0xe4669f39040201f6, 0x7a1d7c218cf04ade,
|
||||
0x65623c29d79ce5ce, 0x2368449096c00bb1, 0xab9bf1879da503ba, 0xbc23ecb1a458058e,
|
||||
0x9a58df01bb401ecc, 0xa070e868a85f143d, 0x4ff188307df2239e, 0x14d565b41a641183,
|
||||
0xee13337452701602, 0x950e3dcf3f285e09, 0x59930254b9c80953, 0x3bf299408930da6d,
|
||||
0xa955943f53691387, 0xa15edecaa9cb8784, 0x29142127352be9a0, 0x76f0371fff4e7afb,
|
||||
0x0239f450274f2228, 0xbb073af01d5e868b, 0xbfc80571c10e96c1, 0xd267088568222e23,
|
||||
0x9671a3d48e80b5b0, 0x55b5d38ae193bb81, 0x693ae2d0a18b04b8, 0x5c48b4ecadd5335f,
|
||||
0xfd743b194916a1ca, 0x2577018134be98c4, 0xe77987e83c54a4ad, 0x28e11014da33e1b9,
|
||||
0x270cc59e226aa213, 0x71495f756d1a5f60, 0x9be853fb60afef77, 0xadc786a7f7443dbf,
|
||||
0x0904456173b29a82, 0x58bc7a66c232bd5e, 0xf306558c673ac8b2, 0x41f639c6b6c9772a,
|
||||
0x216defe99fda35da, 0x11640cc71c7be615, 0x93c43694565c5527, 0xea038e6246777839,
|
||||
0xf9abf3ce5a3e2469, 0x741e768d0fd312d2, 0x0144b883ced652c6, 0xc20b5a5ba33f8552,
|
||||
0x1ae69633c3435a9d, 0x97a28ca4088cfdec, 0x8824a43c1e96f420, 0x37612fa66eeea746,
|
||||
0x6b4cb165f9cf0e5a, 0x43aa1c06a0abfb4a, 0x7f4dc26ff162796b, 0x6cbacc8e54ed9b0f,
|
||||
0xa6b7ffefd2bb253e, 0x2e25bc95b0a29d4f, 0x86d6a58bdef1388c, 0xded74ac576b6f054,
|
||||
0x8030bdbc2b45805d, 0x3c81af70e94d9289, 0x3eff6dda9e3100db, 0xb38dc39fdfcc8847,
|
||||
0x123885528d17b87e, 0xf2da0ed240b1b642, 0x44cefadcd54bf9a9, 0x1312200e433c7ee6,
|
||||
0x9ffcc84f3a78c748, 0xf0cd1f72248576bb, 0xec6974053638cfe4, 0x2ba7b67c0cec4e4c,
|
||||
0xac2f4df3e5ce32ed, 0xcb33d14326ea4c11, 0xa4e9044cc77e58bc, 0x5f513293d934fcef,
|
||||
0x5dc9645506e55444, 0x50de418f317de40a, 0x388cb31a69dde259, 0x2db4a83455820a86,
|
||||
0x9010a91e84711ae9, 0x4df7f0b7b1498371, 0xd62a2eabc0977179, 0x22fac097aa8d5c0e,
|
||||
}
|
||||
|
||||
T3 := [?]u64 {
|
||||
0xf49fcc2ff1daf39b, 0x487fd5c66ff29281, 0xe8a30667fcdca83f, 0x2c9b4be3d2fcce63,
|
||||
0xda3ff74b93fbbbc2, 0x2fa165d2fe70ba66, 0xa103e279970e93d4, 0xbecdec77b0e45e71,
|
||||
0xcfb41e723985e497, 0xb70aaa025ef75017, 0xd42309f03840b8e0, 0x8efc1ad035898579,
|
||||
0x96c6920be2b2abc5, 0x66af4163375a9172, 0x2174abdcca7127fb, 0xb33ccea64a72ff41,
|
||||
0xf04a4933083066a5, 0x8d970acdd7289af5, 0x8f96e8e031c8c25e, 0xf3fec02276875d47,
|
||||
0xec7bf310056190dd, 0xf5adb0aebb0f1491, 0x9b50f8850fd58892, 0x4975488358b74de8,
|
||||
0xa3354ff691531c61, 0x0702bbe481d2c6ee, 0x89fb24057deded98, 0xac3075138596e902,
|
||||
0x1d2d3580172772ed, 0xeb738fc28e6bc30d, 0x5854ef8f63044326, 0x9e5c52325add3bbe,
|
||||
0x90aa53cf325c4623, 0xc1d24d51349dd067, 0x2051cfeea69ea624, 0x13220f0a862e7e4f,
|
||||
0xce39399404e04864, 0xd9c42ca47086fcb7, 0x685ad2238a03e7cc, 0x066484b2ab2ff1db,
|
||||
0xfe9d5d70efbf79ec, 0x5b13b9dd9c481854, 0x15f0d475ed1509ad, 0x0bebcd060ec79851,
|
||||
0xd58c6791183ab7f8, 0xd1187c5052f3eee4, 0xc95d1192e54e82ff, 0x86eea14cb9ac6ca2,
|
||||
0x3485beb153677d5d, 0xdd191d781f8c492a, 0xf60866baa784ebf9, 0x518f643ba2d08c74,
|
||||
0x8852e956e1087c22, 0xa768cb8dc410ae8d, 0x38047726bfec8e1a, 0xa67738b4cd3b45aa,
|
||||
0xad16691cec0dde19, 0xc6d4319380462e07, 0xc5a5876d0ba61938, 0x16b9fa1fa58fd840,
|
||||
0x188ab1173ca74f18, 0xabda2f98c99c021f, 0x3e0580ab134ae816, 0x5f3b05b773645abb,
|
||||
0x2501a2be5575f2f6, 0x1b2f74004e7e8ba9, 0x1cd7580371e8d953, 0x7f6ed89562764e30,
|
||||
0xb15926ff596f003d, 0x9f65293da8c5d6b9, 0x6ecef04dd690f84c, 0x4782275fff33af88,
|
||||
0xe41433083f820801, 0xfd0dfe409a1af9b5, 0x4325a3342cdb396b, 0x8ae77e62b301b252,
|
||||
0xc36f9e9f6655615a, 0x85455a2d92d32c09, 0xf2c7dea949477485, 0x63cfb4c133a39eba,
|
||||
0x83b040cc6ebc5462, 0x3b9454c8fdb326b0, 0x56f56a9e87ffd78c, 0x2dc2940d99f42bc6,
|
||||
0x98f7df096b096e2d, 0x19a6e01e3ad852bf, 0x42a99ccbdbd4b40b, 0xa59998af45e9c559,
|
||||
0x366295e807d93186, 0x6b48181bfaa1f773, 0x1fec57e2157a0a1d, 0x4667446af6201ad5,
|
||||
0xe615ebcacfb0f075, 0xb8f31f4f68290778, 0x22713ed6ce22d11e, 0x3057c1a72ec3c93b,
|
||||
0xcb46acc37c3f1f2f, 0xdbb893fd02aaf50e, 0x331fd92e600b9fcf, 0xa498f96148ea3ad6,
|
||||
0xa8d8426e8b6a83ea, 0xa089b274b7735cdc, 0x87f6b3731e524a11, 0x118808e5cbc96749,
|
||||
0x9906e4c7b19bd394, 0xafed7f7e9b24a20c, 0x6509eadeeb3644a7, 0x6c1ef1d3e8ef0ede,
|
||||
0xb9c97d43e9798fb4, 0xa2f2d784740c28a3, 0x7b8496476197566f, 0x7a5be3e6b65f069d,
|
||||
0xf96330ed78be6f10, 0xeee60de77a076a15, 0x2b4bee4aa08b9bd0, 0x6a56a63ec7b8894e,
|
||||
0x02121359ba34fef4, 0x4cbf99f8283703fc, 0x398071350caf30c8, 0xd0a77a89f017687a,
|
||||
0xf1c1a9eb9e423569, 0x8c7976282dee8199, 0x5d1737a5dd1f7abd, 0x4f53433c09a9fa80,
|
||||
0xfa8b0c53df7ca1d9, 0x3fd9dcbc886ccb77, 0xc040917ca91b4720, 0x7dd00142f9d1dcdf,
|
||||
0x8476fc1d4f387b58, 0x23f8e7c5f3316503, 0x032a2244e7e37339, 0x5c87a5d750f5a74b,
|
||||
0x082b4cc43698992e, 0xdf917becb858f63c, 0x3270b8fc5bf86dda, 0x10ae72bb29b5dd76,
|
||||
0x576ac94e7700362b, 0x1ad112dac61efb8f, 0x691bc30ec5faa427, 0xff246311cc327143,
|
||||
0x3142368e30e53206, 0x71380e31e02ca396, 0x958d5c960aad76f1, 0xf8d6f430c16da536,
|
||||
0xc8ffd13f1be7e1d2, 0x7578ae66004ddbe1, 0x05833f01067be646, 0xbb34b5ad3bfe586d,
|
||||
0x095f34c9a12b97f0, 0x247ab64525d60ca8, 0xdcdbc6f3017477d1, 0x4a2e14d4decad24d,
|
||||
0xbdb5e6d9be0a1eeb, 0x2a7e70f7794301ab, 0xdef42d8a270540fd, 0x01078ec0a34c22c1,
|
||||
0xe5de511af4c16387, 0x7ebb3a52bd9a330a, 0x77697857aa7d6435, 0x004e831603ae4c32,
|
||||
0xe7a21020ad78e312, 0x9d41a70c6ab420f2, 0x28e06c18ea1141e6, 0xd2b28cbd984f6b28,
|
||||
0x26b75f6c446e9d83, 0xba47568c4d418d7f, 0xd80badbfe6183d8e, 0x0e206d7f5f166044,
|
||||
0xe258a43911cbca3e, 0x723a1746b21dc0bc, 0xc7caa854f5d7cdd3, 0x7cac32883d261d9c,
|
||||
0x7690c26423ba942c, 0x17e55524478042b8, 0xe0be477656a2389f, 0x4d289b5e67ab2da0,
|
||||
0x44862b9c8fbbfd31, 0xb47cc8049d141365, 0x822c1b362b91c793, 0x4eb14655fb13dfd8,
|
||||
0x1ecbba0714e2a97b, 0x6143459d5cde5f14, 0x53a8fbf1d5f0ac89, 0x97ea04d81c5e5b00,
|
||||
0x622181a8d4fdb3f3, 0xe9bcd341572a1208, 0x1411258643cce58a, 0x9144c5fea4c6e0a4,
|
||||
0x0d33d06565cf620f, 0x54a48d489f219ca1, 0xc43e5eac6d63c821, 0xa9728b3a72770daf,
|
||||
0xd7934e7b20df87ef, 0xe35503b61a3e86e5, 0xcae321fbc819d504, 0x129a50b3ac60bfa6,
|
||||
0xcd5e68ea7e9fb6c3, 0xb01c90199483b1c7, 0x3de93cd5c295376c, 0xaed52edf2ab9ad13,
|
||||
0x2e60f512c0a07884, 0xbc3d86a3e36210c9, 0x35269d9b163951ce, 0x0c7d6e2ad0cdb5fa,
|
||||
0x59e86297d87f5733, 0x298ef221898db0e7, 0x55000029d1a5aa7e, 0x8bc08ae1b5061b45,
|
||||
0xc2c31c2b6c92703a, 0x94cc596baf25ef42, 0x0a1d73db22540456, 0x04b6a0f9d9c4179a,
|
||||
0xeffdafa2ae3d3c60, 0xf7c8075bb49496c4, 0x9cc5c7141d1cd4e3, 0x78bd1638218e5534,
|
||||
0xb2f11568f850246a, 0xedfabcfa9502bc29, 0x796ce5f2da23051b, 0xaae128b0dc93537c,
|
||||
0x3a493da0ee4b29ae, 0xb5df6b2c416895d7, 0xfcabbd25122d7f37, 0x70810b58105dc4b1,
|
||||
0xe10fdd37f7882a90, 0x524dcab5518a3f5c, 0x3c9e85878451255b, 0x4029828119bd34e2,
|
||||
0x74a05b6f5d3ceccb, 0xb610021542e13eca, 0x0ff979d12f59e2ac, 0x6037da27e4f9cc50,
|
||||
0x5e92975a0df1847d, 0xd66de190d3e623fe, 0x5032d6b87b568048, 0x9a36b7ce8235216e,
|
||||
0x80272a7a24f64b4a, 0x93efed8b8c6916f7, 0x37ddbff44cce1555, 0x4b95db5d4b99bd25,
|
||||
0x92d3fda169812fc0, 0xfb1a4a9a90660bb6, 0x730c196946a4b9b2, 0x81e289aa7f49da68,
|
||||
0x64669a0f83b1a05f, 0x27b3ff7d9644f48b, 0xcc6b615c8db675b3, 0x674f20b9bcebbe95,
|
||||
0x6f31238275655982, 0x5ae488713e45cf05, 0xbf619f9954c21157, 0xeabac46040a8eae9,
|
||||
0x454c6fe9f2c0c1cd, 0x419cf6496412691c, 0xd3dc3bef265b0f70, 0x6d0e60f5c3578a9e,
|
||||
}
|
||||
|
||||
T4 := [?]u64 {
|
||||
0x5b0e608526323c55, 0x1a46c1a9fa1b59f5, 0xa9e245a17c4c8ffa, 0x65ca5159db2955d7,
|
||||
0x05db0a76ce35afc2, 0x81eac77ea9113d45, 0x528ef88ab6ac0a0d, 0xa09ea253597be3ff,
|
||||
0x430ddfb3ac48cd56, 0xc4b3a67af45ce46f, 0x4ececfd8fbe2d05e, 0x3ef56f10b39935f0,
|
||||
0x0b22d6829cd619c6, 0x17fd460a74df2069, 0x6cf8cc8e8510ed40, 0xd6c824bf3a6ecaa7,
|
||||
0x61243d581a817049, 0x048bacb6bbc163a2, 0xd9a38ac27d44cc32, 0x7fddff5baaf410ab,
|
||||
0xad6d495aa804824b, 0xe1a6a74f2d8c9f94, 0xd4f7851235dee8e3, 0xfd4b7f886540d893,
|
||||
0x247c20042aa4bfda, 0x096ea1c517d1327c, 0xd56966b4361a6685, 0x277da5c31221057d,
|
||||
0x94d59893a43acff7, 0x64f0c51ccdc02281, 0x3d33bcc4ff6189db, 0xe005cb184ce66af1,
|
||||
0xff5ccd1d1db99bea, 0xb0b854a7fe42980f, 0x7bd46a6a718d4b9f, 0xd10fa8cc22a5fd8c,
|
||||
0xd31484952be4bd31, 0xc7fa975fcb243847, 0x4886ed1e5846c407, 0x28cddb791eb70b04,
|
||||
0xc2b00be2f573417f, 0x5c9590452180f877, 0x7a6bddfff370eb00, 0xce509e38d6d9d6a4,
|
||||
0xebeb0f00647fa702, 0x1dcc06cf76606f06, 0xe4d9f28ba286ff0a, 0xd85a305dc918c262,
|
||||
0x475b1d8732225f54, 0x2d4fb51668ccb5fe, 0xa679b9d9d72bba20, 0x53841c0d912d43a5,
|
||||
0x3b7eaa48bf12a4e8, 0x781e0e47f22f1ddf, 0xeff20ce60ab50973, 0x20d261d19dffb742,
|
||||
0x16a12b03062a2e39, 0x1960eb2239650495, 0x251c16fed50eb8b8, 0x9ac0c330f826016e,
|
||||
0xed152665953e7671, 0x02d63194a6369570, 0x5074f08394b1c987, 0x70ba598c90b25ce1,
|
||||
0x794a15810b9742f6, 0x0d5925e9fcaf8c6c, 0x3067716cd868744e, 0x910ab077e8d7731b,
|
||||
0x6a61bbdb5ac42f61, 0x93513efbf0851567, 0xf494724b9e83e9d5, 0xe887e1985c09648d,
|
||||
0x34b1d3c675370cfd, 0xdc35e433bc0d255d, 0xd0aab84234131be0, 0x08042a50b48b7eaf,
|
||||
0x9997c4ee44a3ab35, 0x829a7b49201799d0, 0x263b8307b7c54441, 0x752f95f4fd6a6ca6,
|
||||
0x927217402c08c6e5, 0x2a8ab754a795d9ee, 0xa442f7552f72943d, 0x2c31334e19781208,
|
||||
0x4fa98d7ceaee6291, 0x55c3862f665db309, 0xbd0610175d53b1f3, 0x46fe6cb840413f27,
|
||||
0x3fe03792df0cfa59, 0xcfe700372eb85e8f, 0xa7be29e7adbce118, 0xe544ee5cde8431dd,
|
||||
0x8a781b1b41f1873e, 0xa5c94c78a0d2f0e7, 0x39412e2877b60728, 0xa1265ef3afc9a62c,
|
||||
0xbcc2770c6a2506c5, 0x3ab66dd5dce1ce12, 0xe65499d04a675b37, 0x7d8f523481bfd216,
|
||||
0x0f6f64fcec15f389, 0x74efbe618b5b13c8, 0xacdc82b714273e1d, 0xdd40bfe003199d17,
|
||||
0x37e99257e7e061f8, 0xfa52626904775aaa, 0x8bbbf63a463d56f9, 0xf0013f1543a26e64,
|
||||
0xa8307e9f879ec898, 0xcc4c27a4150177cc, 0x1b432f2cca1d3348, 0xde1d1f8f9f6fa013,
|
||||
0x606602a047a7ddd6, 0xd237ab64cc1cb2c7, 0x9b938e7225fcd1d3, 0xec4e03708e0ff476,
|
||||
0xfeb2fbda3d03c12d, 0xae0bced2ee43889a, 0x22cb8923ebfb4f43, 0x69360d013cf7396d,
|
||||
0x855e3602d2d4e022, 0x073805bad01f784c, 0x33e17a133852f546, 0xdf4874058ac7b638,
|
||||
0xba92b29c678aa14a, 0x0ce89fc76cfaadcd, 0x5f9d4e0908339e34, 0xf1afe9291f5923b9,
|
||||
0x6e3480f60f4a265f, 0xeebf3a2ab29b841c, 0xe21938a88f91b4ad, 0x57dfeff845c6d3c3,
|
||||
0x2f006b0bf62caaf2, 0x62f479ef6f75ee78, 0x11a55ad41c8916a9, 0xf229d29084fed453,
|
||||
0x42f1c27b16b000e6, 0x2b1f76749823c074, 0x4b76eca3c2745360, 0x8c98f463b91691bd,
|
||||
0x14bcc93cf1ade66a, 0x8885213e6d458397, 0x8e177df0274d4711, 0xb49b73b5503f2951,
|
||||
0x10168168c3f96b6b, 0x0e3d963b63cab0ae, 0x8dfc4b5655a1db14, 0xf789f1356e14de5c,
|
||||
0x683e68af4e51dac1, 0xc9a84f9d8d4b0fd9, 0x3691e03f52a0f9d1, 0x5ed86e46e1878e80,
|
||||
0x3c711a0e99d07150, 0x5a0865b20c4e9310, 0x56fbfc1fe4f0682e, 0xea8d5de3105edf9b,
|
||||
0x71abfdb12379187a, 0x2eb99de1bee77b9c, 0x21ecc0ea33cf4523, 0x59a4d7521805c7a1,
|
||||
0x3896f5eb56ae7c72, 0xaa638f3db18f75dc, 0x9f39358dabe9808e, 0xb7defa91c00b72ac,
|
||||
0x6b5541fd62492d92, 0x6dc6dee8f92e4d5b, 0x353f57abc4beea7e, 0x735769d6da5690ce,
|
||||
0x0a234aa642391484, 0xf6f9508028f80d9d, 0xb8e319a27ab3f215, 0x31ad9c1151341a4d,
|
||||
0x773c22a57bef5805, 0x45c7561a07968633, 0xf913da9e249dbe36, 0xda652d9b78a64c68,
|
||||
0x4c27a97f3bc334ef, 0x76621220e66b17f4, 0x967743899acd7d0b, 0xf3ee5bcae0ed6782,
|
||||
0x409f753600c879fc, 0x06d09a39b5926db6, 0x6f83aeb0317ac588, 0x01e6ca4a86381f21,
|
||||
0x66ff3462d19f3025, 0x72207c24ddfd3bfb, 0x4af6b6d3e2ece2eb, 0x9c994dbec7ea08de,
|
||||
0x49ace597b09a8bc4, 0xb38c4766cf0797ba, 0x131b9373c57c2a75, 0xb1822cce61931e58,
|
||||
0x9d7555b909ba1c0c, 0x127fafdd937d11d2, 0x29da3badc66d92e4, 0xa2c1d57154c2ecbc,
|
||||
0x58c5134d82f6fe24, 0x1c3ae3515b62274f, 0xe907c82e01cb8126, 0xf8ed091913e37fcb,
|
||||
0x3249d8f9c80046c9, 0x80cf9bede388fb63, 0x1881539a116cf19e, 0x5103f3f76bd52457,
|
||||
0x15b7e6f5ae47f7a8, 0xdbd7c6ded47e9ccf, 0x44e55c410228bb1a, 0xb647d4255edb4e99,
|
||||
0x5d11882bb8aafc30, 0xf5098bbb29d3212a, 0x8fb5ea14e90296b3, 0x677b942157dd025a,
|
||||
0xfb58e7c0a390acb5, 0x89d3674c83bd4a01, 0x9e2da4df4bf3b93b, 0xfcc41e328cab4829,
|
||||
0x03f38c96ba582c52, 0xcad1bdbd7fd85db2, 0xbbb442c16082ae83, 0xb95fe86ba5da9ab0,
|
||||
0xb22e04673771a93f, 0x845358c9493152d8, 0xbe2a488697b4541e, 0x95a2dc2dd38e6966,
|
||||
0xc02c11ac923c852b, 0x2388b1990df2a87b, 0x7c8008fa1b4f37be, 0x1f70d0c84d54e503,
|
||||
0x5490adec7ece57d4, 0x002b3c27d9063a3a, 0x7eaea3848030a2bf, 0xc602326ded2003c0,
|
||||
0x83a7287d69a94086, 0xc57a5fcb30f57a8a, 0xb56844e479ebe779, 0xa373b40f05dcbce9,
|
||||
0xd71a786e88570ee2, 0x879cbacdbde8f6a0, 0x976ad1bcc164a32f, 0xab21e25e9666d78b,
|
||||
0x901063aae5e5c33c, 0x9818b34448698d90, 0xe36487ae3e1e8abb, 0xafbdf931893bdcb4,
|
||||
0x6345a0dc5fbbd519, 0x8628fe269b9465ca, 0x1e5d01603f9c51ec, 0x4de44006a15049b7,
|
||||
0xbf6c70e5f776cbb1, 0x411218f2ef552bed, 0xcb0c0708705a36a3, 0xe74d14754f986044,
|
||||
0xcd56d9430ea8280e, 0xc12591d7535f5065, 0xc83223f1720aef96, 0xc3a0396f7363a51f,
|
||||
}
|
||||
|
||||
Tiger_Context :: struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
x: [64]byte,
|
||||
nx: int,
|
||||
length: u64,
|
||||
ver: int,
|
||||
}
|
||||
|
||||
round :: #force_inline proc "contextless" (a, b, c, x, mul: u64) -> (u64, u64, u64) {
|
||||
a, b, c := a, b, c
|
||||
c ~= x
|
||||
a -= T1[c & 0xff] ~ T2[(c >> 16) & 0xff] ~ T3[(c >> 32) & 0xff] ~ T4[(c >> 48) & 0xff]
|
||||
b += T4[(c >> 8) & 0xff] ~ T3[(c >> 24) & 0xff] ~ T2[(c >> 40) & 0xff] ~ T1[(c >> 56) & 0xff]
|
||||
b *= mul
|
||||
return a, b, c
|
||||
}
|
||||
|
||||
pass :: #force_inline proc "contextless" (a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) {
|
||||
x, y, z = round(a, b, c, d[0], mul)
|
||||
y, z, x = round(y, z, x, d[1], mul)
|
||||
z, x, y = round(z, x, y, d[2], mul)
|
||||
x, y, z = round(x, y, z, d[3], mul)
|
||||
y, z, x = round(y, z, x, d[4], mul)
|
||||
z, x, y = round(z, x, y, d[5], mul)
|
||||
x, y, z = round(x, y, z, d[6], mul)
|
||||
y, z, x = round(y, z, x, d[7], mul)
|
||||
return
|
||||
}
|
||||
|
||||
key_schedule :: #force_inline proc "contextless" (x: []u64) {
|
||||
x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5
|
||||
x[1] ~= x[0]
|
||||
x[2] += x[1]
|
||||
x[3] -= x[2] ~ ((~x[1]) << 19)
|
||||
x[4] ~= x[3]
|
||||
x[5] += x[4]
|
||||
x[6] -= x[5] ~ ((~x[4]) >> 23)
|
||||
x[7] ~= x[6]
|
||||
x[0] += x[7]
|
||||
x[1] -= x[0] ~ ((~x[7]) << 19)
|
||||
x[2] ~= x[1]
|
||||
x[3] += x[2]
|
||||
x[4] -= x[3] ~ ((~x[2]) >> 23)
|
||||
x[5] ~= x[4]
|
||||
x[6] += x[5]
|
||||
x[7] -= x[6] ~ 0x0123456789abcdef
|
||||
}
|
||||
|
||||
compress :: #force_inline proc "contextless" (ctx: ^Tiger_Context, data: []byte) {
|
||||
a := ctx.a
|
||||
b := ctx.b
|
||||
c := ctx.c
|
||||
x := util.cast_slice([]u64, data)
|
||||
ctx.a, ctx.b, ctx.c = pass(ctx.a, ctx.b, ctx.c, x, 5)
|
||||
key_schedule(x)
|
||||
ctx.c, ctx.a, ctx.b = pass(ctx.c, ctx.a, ctx.b, x, 7)
|
||||
key_schedule(x)
|
||||
ctx.b, ctx.c, ctx.a = pass(ctx.b, ctx.c, ctx.a, x, 9)
|
||||
ctx.a ~= a
|
||||
ctx.b -= b
|
||||
ctx.c += c
|
||||
}
|
||||
|
||||
init :: proc "contextless" (ctx: ^Tiger_Context) {
|
||||
ctx.a = 0x0123456789abcdef
|
||||
ctx.b = 0xfedcba9876543210
|
||||
ctx.c = 0xf096a5b4c3b2e187
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Tiger_Context, input: []byte) {
|
||||
p := make([]byte, len(input))
|
||||
copy(p, input)
|
||||
|
||||
length := len(p)
|
||||
ctx.length += u64(length)
|
||||
if ctx.nx > 0 {
|
||||
n := len(p)
|
||||
if n > 64 - ctx.nx {
|
||||
n = 64 - ctx.nx
|
||||
}
|
||||
copy(ctx.x[ctx.nx:ctx.nx + n], p[:n])
|
||||
ctx.nx += n
|
||||
if ctx.nx == 64 {
|
||||
compress(ctx, ctx.x[:64 - 1])
|
||||
ctx.nx = 0
|
||||
}
|
||||
p = p[n:]
|
||||
}
|
||||
for len(p) >= 64 {
|
||||
compress(ctx, p[:64])
|
||||
p = p[64:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], p)
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Tiger_Context, hash: []byte) {
|
||||
length := ctx.length
|
||||
tmp: [64]byte
|
||||
if ctx.ver == 1 {
|
||||
tmp[0] = 0x01
|
||||
} else {
|
||||
tmp[0] = 0x80
|
||||
}
|
||||
|
||||
size := length & 0x3f
|
||||
if size < 56 {
|
||||
update(ctx, tmp[:56 - size])
|
||||
} else {
|
||||
update(ctx, tmp[:64 + 56 - size])
|
||||
}
|
||||
|
||||
length <<= 3
|
||||
for i := uint(0); i < 8; i += 1 {
|
||||
tmp[i] = byte(length >> (8 * i))
|
||||
}
|
||||
update(ctx, tmp[:8])
|
||||
|
||||
for i := uint(0); i < 8; i += 1 {
|
||||
tmp[i] = byte(ctx.a >> (8 * i))
|
||||
tmp[i + 8] = byte(ctx.b >> (8 * i))
|
||||
tmp[i + 16] = byte(ctx.c >> (8 * i))
|
||||
}
|
||||
copy(hash[:], tmp[:len(hash)])
|
||||
}
|
||||
@@ -1,726 +0,0 @@
|
||||
package blake
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Implementation of the BLAKE hashing algorithm, as defined in <https://web.archive.org/web/20190915215948/https://131002.net/blake>
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
DIGEST_SIZE_224 :: 28
|
||||
DIGEST_SIZE_256 :: 32
|
||||
DIGEST_SIZE_384 :: 48
|
||||
DIGEST_SIZE_512 :: 64
|
||||
|
||||
// hash_string_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_224 :: proc "contextless" (data: string) -> [DIGEST_SIZE_224]byte {
|
||||
return hash_bytes_224(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_224 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_224 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// 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_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_224 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
hash: [DIGEST_SIZE_224]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = true
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_224 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_224(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_224(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_224]byte{}, false
|
||||
}
|
||||
|
||||
hash_224 :: proc {
|
||||
hash_stream_224,
|
||||
hash_file_224,
|
||||
hash_bytes_224,
|
||||
hash_string_224,
|
||||
hash_bytes_to_buffer_224,
|
||||
hash_string_to_buffer_224,
|
||||
}
|
||||
|
||||
// hash_string_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_256 :: proc "contextless" (data: string) -> [DIGEST_SIZE_256]byte {
|
||||
return hash_bytes_256(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_256 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_256 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// 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_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_256 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
hash: [DIGEST_SIZE_256]byte
|
||||
ctx: Blake256_Context
|
||||
ctx.is224 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_256 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_256(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_256(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_256]byte{}, false
|
||||
}
|
||||
|
||||
hash_256 :: proc {
|
||||
hash_stream_256,
|
||||
hash_file_256,
|
||||
hash_bytes_256,
|
||||
hash_string_256,
|
||||
hash_bytes_to_buffer_256,
|
||||
hash_string_to_buffer_256,
|
||||
}
|
||||
|
||||
// hash_string_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_384 :: proc "contextless" (data: string) -> [DIGEST_SIZE_384]byte {
|
||||
return hash_bytes_384(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_384 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_384 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// 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_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_384 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
hash: [DIGEST_SIZE_384]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = true
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_384 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_384(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_384(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_384]byte{}, false
|
||||
}
|
||||
|
||||
hash_384 :: proc {
|
||||
hash_stream_384,
|
||||
hash_file_384,
|
||||
hash_bytes_384,
|
||||
hash_string_384,
|
||||
hash_bytes_to_buffer_384,
|
||||
hash_string_to_buffer_384,
|
||||
}
|
||||
|
||||
// hash_string_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string_512 :: proc "contextless" (data: string) -> [DIGEST_SIZE_512]byte {
|
||||
return hash_bytes_512(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes_512 will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer_512 will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// 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_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream_512 will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
hash: [DIGEST_SIZE_512]byte
|
||||
ctx: Blake512_Context
|
||||
ctx.is384 = false
|
||||
init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file_512 will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream_512(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes_512(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE_512]byte{}, false
|
||||
}
|
||||
|
||||
hash_512 :: proc {
|
||||
hash_stream_512,
|
||||
hash_file_512,
|
||||
hash_bytes_512,
|
||||
hash_string_512,
|
||||
hash_bytes_to_buffer_512,
|
||||
hash_string_to_buffer_512,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc "contextless" (ctx: ^$T) {
|
||||
when T == Blake256_Context {
|
||||
if ctx.is224 {
|
||||
ctx.h[0] = 0xc1059ed8
|
||||
ctx.h[1] = 0x367cd507
|
||||
ctx.h[2] = 0x3070dd17
|
||||
ctx.h[3] = 0xf70e5939
|
||||
ctx.h[4] = 0xffc00b31
|
||||
ctx.h[5] = 0x68581511
|
||||
ctx.h[6] = 0x64f98fa7
|
||||
ctx.h[7] = 0xbefa4fa4
|
||||
} else {
|
||||
ctx.h[0] = 0x6a09e667
|
||||
ctx.h[1] = 0xbb67ae85
|
||||
ctx.h[2] = 0x3c6ef372
|
||||
ctx.h[3] = 0xa54ff53a
|
||||
ctx.h[4] = 0x510e527f
|
||||
ctx.h[5] = 0x9b05688c
|
||||
ctx.h[6] = 0x1f83d9ab
|
||||
ctx.h[7] = 0x5be0cd19
|
||||
}
|
||||
} else when T == Blake512_Context {
|
||||
if ctx.is384 {
|
||||
ctx.h[0] = 0xcbbb9d5dc1059ed8
|
||||
ctx.h[1] = 0x629a292a367cd507
|
||||
ctx.h[2] = 0x9159015a3070dd17
|
||||
ctx.h[3] = 0x152fecd8f70e5939
|
||||
ctx.h[4] = 0x67332667ffc00b31
|
||||
ctx.h[5] = 0x8eb44a8768581511
|
||||
ctx.h[6] = 0xdb0c2e0d64f98fa7
|
||||
ctx.h[7] = 0x47b5481dbefa4fa4
|
||||
} else {
|
||||
ctx.h[0] = 0x6a09e667f3bcc908
|
||||
ctx.h[1] = 0xbb67ae8584caa73b
|
||||
ctx.h[2] = 0x3c6ef372fe94f82b
|
||||
ctx.h[3] = 0xa54ff53a5f1d36f1
|
||||
ctx.h[4] = 0x510e527fade682d1
|
||||
ctx.h[5] = 0x9b05688c2b3e6c1f
|
||||
ctx.h[6] = 0x1f83d9abfb41bd6b
|
||||
ctx.h[7] = 0x5be0cd19137e2179
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^$T, data: []byte) {
|
||||
data := data
|
||||
when T == Blake256_Context {
|
||||
if ctx.nx > 0 {
|
||||
n := copy(ctx.x[ctx.nx:], data)
|
||||
ctx.nx += n
|
||||
if ctx.nx == BLOCKSIZE_256 {
|
||||
block256(ctx, ctx.x[:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCKSIZE_256 {
|
||||
n := len(data) &~ (BLOCKSIZE_256 - 1)
|
||||
block256(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], data)
|
||||
}
|
||||
} else when T == Blake512_Context {
|
||||
if ctx.nx > 0 {
|
||||
n := copy(ctx.x[ctx.nx:], data)
|
||||
ctx.nx += n
|
||||
if ctx.nx == BLOCKSIZE_512 {
|
||||
block512(ctx, ctx.x[:])
|
||||
ctx.nx = 0
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) >= BLOCKSIZE_512 {
|
||||
n := len(data) &~ (BLOCKSIZE_512 - 1)
|
||||
block512(ctx, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
if len(data) > 0 {
|
||||
ctx.nx = copy(ctx.x[:], data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^$T, hash: []byte) {
|
||||
when T == Blake256_Context {
|
||||
tmp: [65]byte
|
||||
} else when T == Blake512_Context {
|
||||
tmp: [129]byte
|
||||
}
|
||||
nx := u64(ctx.nx)
|
||||
tmp[0] = 0x80
|
||||
length := (ctx.t + nx) << 3
|
||||
|
||||
when T == Blake256_Context {
|
||||
if nx == 55 {
|
||||
if ctx.is224 {
|
||||
write_additional(ctx, {0x80})
|
||||
} else {
|
||||
write_additional(ctx, {0x81})
|
||||
}
|
||||
} else {
|
||||
if nx < 55 {
|
||||
if nx == 0 {
|
||||
ctx.nullt = true
|
||||
}
|
||||
write_additional(ctx, tmp[0 : 55 - nx])
|
||||
} else {
|
||||
write_additional(ctx, tmp[0 : 64 - nx])
|
||||
write_additional(ctx, tmp[1:56])
|
||||
ctx.nullt = true
|
||||
}
|
||||
if ctx.is224 {
|
||||
write_additional(ctx, {0x00})
|
||||
} else {
|
||||
write_additional(ctx, {0x01})
|
||||
}
|
||||
}
|
||||
|
||||
for i : uint = 0; i < 8; i += 1 {
|
||||
tmp[i] = byte(length >> (56 - 8 * i))
|
||||
}
|
||||
write_additional(ctx, tmp[0:8])
|
||||
|
||||
h := ctx.h[:]
|
||||
if ctx.is224 {
|
||||
h = h[0:7]
|
||||
}
|
||||
for s, i in h {
|
||||
hash[i * 4] = byte(s >> 24)
|
||||
hash[i * 4 + 1] = byte(s >> 16)
|
||||
hash[i * 4 + 2] = byte(s >> 8)
|
||||
hash[i * 4 + 3] = byte(s)
|
||||
}
|
||||
} else when T == Blake512_Context {
|
||||
if nx == 111 {
|
||||
if ctx.is384 {
|
||||
write_additional(ctx, {0x80})
|
||||
} else {
|
||||
write_additional(ctx, {0x81})
|
||||
}
|
||||
} else {
|
||||
if nx < 111 {
|
||||
if nx == 0 {
|
||||
ctx.nullt = true
|
||||
}
|
||||
write_additional(ctx, tmp[0 : 111 - nx])
|
||||
} else {
|
||||
write_additional(ctx, tmp[0 : 128 - nx])
|
||||
write_additional(ctx, tmp[1:112])
|
||||
ctx.nullt = true
|
||||
}
|
||||
if ctx.is384 {
|
||||
write_additional(ctx, {0x00})
|
||||
} else {
|
||||
write_additional(ctx, {0x01})
|
||||
}
|
||||
}
|
||||
|
||||
for i : uint = 0; i < 16; i += 1 {
|
||||
tmp[i] = byte(length >> (120 - 8 * i))
|
||||
}
|
||||
write_additional(ctx, tmp[0:16])
|
||||
|
||||
h := ctx.h[:]
|
||||
if ctx.is384 {
|
||||
h = h[0:6]
|
||||
}
|
||||
for s, i in h {
|
||||
hash[i * 8] = byte(s >> 56)
|
||||
hash[i * 8 + 1] = byte(s >> 48)
|
||||
hash[i * 8 + 2] = byte(s >> 40)
|
||||
hash[i * 8 + 3] = byte(s >> 32)
|
||||
hash[i * 8 + 4] = byte(s >> 24)
|
||||
hash[i * 8 + 5] = byte(s >> 16)
|
||||
hash[i * 8 + 6] = byte(s >> 8)
|
||||
hash[i * 8 + 7] = byte(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SIZE_224 :: 28
|
||||
SIZE_256 :: 32
|
||||
SIZE_384 :: 48
|
||||
SIZE_512 :: 64
|
||||
BLOCKSIZE_256 :: 64
|
||||
BLOCKSIZE_512 :: 128
|
||||
|
||||
Blake256_Context :: struct {
|
||||
h: [8]u32,
|
||||
s: [4]u32,
|
||||
t: u64,
|
||||
x: [64]byte,
|
||||
nx: int,
|
||||
is224: bool,
|
||||
nullt: bool,
|
||||
}
|
||||
|
||||
Blake512_Context :: struct {
|
||||
h: [8]u64,
|
||||
s: [4]u64,
|
||||
t: u64,
|
||||
x: [128]byte,
|
||||
nx: int,
|
||||
is384: bool,
|
||||
nullt: bool,
|
||||
}
|
||||
|
||||
SIGMA := [?]int {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
||||
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
|
||||
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
|
||||
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
|
||||
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
|
||||
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
|
||||
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
|
||||
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
|
||||
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
|
||||
}
|
||||
|
||||
U256 := [16]u32 {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
}
|
||||
|
||||
U512 := [16]u64 {
|
||||
0x243f6a8885a308d3, 0x13198a2e03707344, 0xa4093822299f31d0, 0x082efa98ec4e6c89,
|
||||
0x452821e638d01377, 0xbe5466cf34e90c6c, 0xc0ac29b7c97c50dd, 0x3f84d5b5b5470917,
|
||||
0x9216d5d98979fb1b, 0xd1310ba698dfb5ac, 0x2ffd72dbd01adfb7, 0xb8e1afed6a267e96,
|
||||
0xba7c9045f12c7f99, 0x24a19947b3916cf7, 0x0801f2e2858efc16, 0x636920d871574e69,
|
||||
}
|
||||
|
||||
G256 :: #force_inline proc "contextless" (a, b, c, d: u32, m: [16]u32, i, j: int) -> (u32, u32, u32, u32) {
|
||||
a, b, c, d := a, b, c, d
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (32 - 16) | d >> 16
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (32 - 12) | b >> 12
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (32 - 8) | d >> 8
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (32 - 7) | b >> 7
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int) -> (u64, u64, u64, u64) {
|
||||
a, b, c, d := a, b, c, d
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (64 - 32) | d >> 32
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (64 - 25) | b >> 25
|
||||
a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j)]]
|
||||
a += b
|
||||
d ~= a
|
||||
d = d << (64 - 16) | d >> 16
|
||||
c += d
|
||||
b ~= c
|
||||
b = b << (64 - 11) | b >> 11
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check {
|
||||
i, j: int = ---, ---
|
||||
v, m: [16]u32 = ---, ---
|
||||
p := p
|
||||
for len(p) >= BLOCKSIZE_256 {
|
||||
v[0] = ctx.h[0]
|
||||
v[1] = ctx.h[1]
|
||||
v[2] = ctx.h[2]
|
||||
v[3] = ctx.h[3]
|
||||
v[4] = ctx.h[4]
|
||||
v[5] = ctx.h[5]
|
||||
v[6] = ctx.h[6]
|
||||
v[7] = ctx.h[7]
|
||||
v[8] = ctx.s[0] ~ U256[0]
|
||||
v[9] = ctx.s[1] ~ U256[1]
|
||||
v[10] = ctx.s[2] ~ U256[2]
|
||||
v[11] = ctx.s[3] ~ U256[3]
|
||||
v[12] = U256[4]
|
||||
v[13] = U256[5]
|
||||
v[14] = U256[6]
|
||||
v[15] = U256[7]
|
||||
|
||||
ctx.t += 512
|
||||
if !ctx.nullt {
|
||||
v[12] ~= u32(ctx.t)
|
||||
v[13] ~= u32(ctx.t)
|
||||
v[14] ~= u32(ctx.t >> 32)
|
||||
v[15] ~= u32(ctx.t >> 32)
|
||||
}
|
||||
|
||||
for i, j = 0, 0; i < 16; i, j = i+1, j+4 {
|
||||
m[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3])
|
||||
}
|
||||
|
||||
for i = 0; i < 14; i += 1 {
|
||||
v[0], v[4], v[8], v[12] = G256(v[0], v[4], v[8], v[12], m, i, 0)
|
||||
v[1], v[5], v[9], v[13] = G256(v[1], v[5], v[9], v[13], m, i, 1)
|
||||
v[2], v[6], v[10], v[14] = G256(v[2], v[6], v[10], v[14], m, i, 2)
|
||||
v[3], v[7], v[11], v[15] = G256(v[3], v[7], v[11], v[15], m, i, 3)
|
||||
v[0], v[5], v[10], v[15] = G256(v[0], v[5], v[10], v[15], m, i, 4)
|
||||
v[1], v[6], v[11], v[12] = G256(v[1], v[6], v[11], v[12], m, i, 5)
|
||||
v[2], v[7], v[8], v[13] = G256(v[2], v[7], v[8], v[13], m, i, 6)
|
||||
v[3], v[4], v[9], v[14] = G256(v[3], v[4], v[9], v[14], m, i, 7)
|
||||
}
|
||||
|
||||
for i = 0; i < 8; i += 1 {
|
||||
ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
|
||||
}
|
||||
p = p[BLOCKSIZE_256:]
|
||||
}
|
||||
}
|
||||
|
||||
block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check {
|
||||
i, j: int = ---, ---
|
||||
v, m: [16]u64 = ---, ---
|
||||
p := p
|
||||
for len(p) >= BLOCKSIZE_512 {
|
||||
v[0] = ctx.h[0]
|
||||
v[1] = ctx.h[1]
|
||||
v[2] = ctx.h[2]
|
||||
v[3] = ctx.h[3]
|
||||
v[4] = ctx.h[4]
|
||||
v[5] = ctx.h[5]
|
||||
v[6] = ctx.h[6]
|
||||
v[7] = ctx.h[7]
|
||||
v[8] = ctx.s[0] ~ U512[0]
|
||||
v[9] = ctx.s[1] ~ U512[1]
|
||||
v[10] = ctx.s[2] ~ U512[2]
|
||||
v[11] = ctx.s[3] ~ U512[3]
|
||||
v[12] = U512[4]
|
||||
v[13] = U512[5]
|
||||
v[14] = U512[6]
|
||||
v[15] = U512[7]
|
||||
|
||||
ctx.t += 1024
|
||||
if !ctx.nullt {
|
||||
v[12] ~= ctx.t
|
||||
v[13] ~= ctx.t
|
||||
v[14] ~= 0
|
||||
v[15] ~= 0
|
||||
}
|
||||
|
||||
for i, j = 0, 0; i < 16; i, j = i + 1, j + 8 {
|
||||
m[i] = u64(p[j]) << 56 | u64(p[j + 1]) << 48 | u64(p[j + 2]) << 40 | u64(p[j + 3]) << 32 |
|
||||
u64(p[j + 4]) << 24 | u64(p[j + 5]) << 16 | u64(p[j + 6]) << 8 | u64(p[j + 7])
|
||||
}
|
||||
for i = 0; i < 16; i += 1 {
|
||||
v[0], v[4], v[8], v[12] = G512(v[0], v[4], v[8], v[12], m, i, 0)
|
||||
v[1], v[5], v[9], v[13] = G512(v[1], v[5], v[9], v[13], m, i, 1)
|
||||
v[2], v[6], v[10], v[14] = G512(v[2], v[6], v[10], v[14], m, i, 2)
|
||||
v[3], v[7], v[11], v[15] = G512(v[3], v[7], v[11], v[15], m, i, 3)
|
||||
v[0], v[5], v[10], v[15] = G512(v[0], v[5], v[10], v[15], m, i, 4)
|
||||
v[1], v[6], v[11], v[12] = G512(v[1], v[6], v[11], v[12], m, i, 5)
|
||||
v[2], v[7], v[8], v[13] = G512(v[2], v[7], v[8], v[13], m, i, 6)
|
||||
v[3], v[4], v[9], v[14] = G512(v[3], v[4], v[9], v[14], m, i, 7)
|
||||
}
|
||||
|
||||
for i = 0; i < 8; i += 1 {
|
||||
ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
|
||||
}
|
||||
p = p[BLOCKSIZE_512:]
|
||||
}
|
||||
}
|
||||
|
||||
write_additional :: proc "contextless" (ctx: ^$T, data: []byte) {
|
||||
ctx.t -= u64(len(data)) << 3
|
||||
update(ctx, data)
|
||||
}
|
||||
@@ -7,12 +7,12 @@ package blake2b
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the BLAKE2B hashing algorithm.
|
||||
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
|
||||
Interface for the BLAKE2b hashing algorithm.
|
||||
BLAKE2b and BLAKE2s share the implementation in the _blake2 package.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
|
||||
import "../_blake2"
|
||||
|
||||
@@ -25,103 +25,103 @@ DIGEST_SIZE :: 64
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2b_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// 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_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
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _blake2.Blake2b_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash)
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2b_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_blake2.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2B_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Blake2b_Context :: _blake2.Blake2b_Context
|
||||
Context :: _blake2.Blake2b_Context
|
||||
|
||||
init :: proc(ctx: ^_blake2.Blake2b_Context) {
|
||||
_blake2.init(ctx)
|
||||
init :: proc(ctx: ^Context) {
|
||||
_blake2.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ package blake2s
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
|
||||
Interface for the BLAKE2S hashing algorithm.
|
||||
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
|
||||
Interface for the BLAKE2s hashing algorithm.
|
||||
BLAKE2s and BLAKE2b share the implementation in the _blake2 package.
|
||||
*/
|
||||
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
|
||||
import "../_blake2"
|
||||
|
||||
@@ -25,103 +25,103 @@ DIGEST_SIZE :: 32
|
||||
// hash_string will hash the given input and return the
|
||||
// computed hash
|
||||
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
return hash_bytes(transmute([]byte)(data))
|
||||
}
|
||||
|
||||
// hash_bytes will hash the given input and return the
|
||||
// computed hash
|
||||
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2s_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
|
||||
// hash_string_to_buffer will hash the given input and assign the
|
||||
// computed hash to the second parameter.
|
||||
// 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_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
|
||||
// computed hash into the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_bytes_to_buffer :: proc(data, hash: []byte) {
|
||||
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
|
||||
ctx: _blake2.Blake2s_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
_blake2.update(&ctx, data)
|
||||
_blake2.final(&ctx, hash)
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
update(&ctx, data)
|
||||
final(&ctx, hash)
|
||||
}
|
||||
|
||||
// hash_stream will read the stream in chunks and compute a
|
||||
// hash from its contents
|
||||
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: _blake2.Blake2s_Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
_blake2.init(&ctx)
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = s->impl_read(buf)
|
||||
if read > 0 {
|
||||
_blake2.update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
_blake2.final(&ctx, hash[:])
|
||||
return hash, true
|
||||
hash: [DIGEST_SIZE]byte
|
||||
ctx: Context
|
||||
cfg: _blake2.Blake2_Config
|
||||
cfg.size = _blake2.BLAKE2S_SIZE
|
||||
ctx.cfg = cfg
|
||||
init(&ctx)
|
||||
|
||||
buf := make([]byte, 512)
|
||||
defer delete(buf)
|
||||
|
||||
read := 1
|
||||
for read > 0 {
|
||||
read, _ = io.read(s, buf)
|
||||
if read > 0 {
|
||||
update(&ctx, buf[:read])
|
||||
}
|
||||
}
|
||||
final(&ctx, hash[:])
|
||||
return hash, true
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle
|
||||
// and compute a hash
|
||||
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
if !load_at_once {
|
||||
return hash_stream(os.stream_from_handle(hd))
|
||||
} else {
|
||||
if buf, ok := os.read_entire_file(hd); ok {
|
||||
return hash_bytes(buf[:]), ok
|
||||
}
|
||||
}
|
||||
return [DIGEST_SIZE]byte{}, false
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
Blake2s_Context :: _blake2.Blake2b_Context
|
||||
Context :: _blake2.Blake2s_Context
|
||||
|
||||
init :: proc(ctx: ^_blake2.Blake2s_Context) {
|
||||
_blake2.init(ctx)
|
||||
init :: proc(ctx: ^Context) {
|
||||
_blake2.init(ctx)
|
||||
}
|
||||
|
||||
update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
_blake2.update(ctx, data)
|
||||
}
|
||||
|
||||
final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
final :: proc(ctx: ^Context, hash: []byte) {
|
||||
_blake2.final(ctx, hash)
|
||||
}
|
||||
|
||||
+145
-180
@@ -1,6 +1,6 @@
|
||||
package chacha20
|
||||
|
||||
import "core:crypto/util"
|
||||
import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
import "core:mem"
|
||||
|
||||
@@ -8,15 +8,23 @@ KEY_SIZE :: 32
|
||||
NONCE_SIZE :: 12
|
||||
XNONCE_SIZE :: 24
|
||||
|
||||
@(private)
|
||||
_MAX_CTR_IETF :: 0xffffffff
|
||||
|
||||
@(private)
|
||||
_BLOCK_SIZE :: 64
|
||||
@(private)
|
||||
_STATE_SIZE_U32 :: 16
|
||||
@(private)
|
||||
_ROUNDS :: 20
|
||||
|
||||
@(private)
|
||||
_SIGMA_0 : u32 : 0x61707865
|
||||
@(private)
|
||||
_SIGMA_1 : u32 : 0x3320646e
|
||||
@(private)
|
||||
_SIGMA_2 : u32 : 0x79622d32
|
||||
@(private)
|
||||
_SIGMA_3 : u32 : 0x6b206574
|
||||
|
||||
Context :: struct {
|
||||
@@ -52,23 +60,23 @@ init :: proc (ctx: ^Context, key, nonce: []byte) {
|
||||
ctx._s[1] = _SIGMA_1
|
||||
ctx._s[2] = _SIGMA_2
|
||||
ctx._s[3] = _SIGMA_3
|
||||
ctx._s[4] = util.U32_LE(k[0:4])
|
||||
ctx._s[5] = util.U32_LE(k[4:8])
|
||||
ctx._s[6] = util.U32_LE(k[8:12])
|
||||
ctx._s[7] = util.U32_LE(k[12:16])
|
||||
ctx._s[8] = util.U32_LE(k[16:20])
|
||||
ctx._s[9] = util.U32_LE(k[20:24])
|
||||
ctx._s[10] = util.U32_LE(k[24:28])
|
||||
ctx._s[11] = util.U32_LE(k[28:32])
|
||||
ctx._s[4] = endian.unchecked_get_u32le(k[0:4])
|
||||
ctx._s[5] = endian.unchecked_get_u32le(k[4:8])
|
||||
ctx._s[6] = endian.unchecked_get_u32le(k[8:12])
|
||||
ctx._s[7] = endian.unchecked_get_u32le(k[12:16])
|
||||
ctx._s[8] = endian.unchecked_get_u32le(k[16:20])
|
||||
ctx._s[9] = endian.unchecked_get_u32le(k[20:24])
|
||||
ctx._s[10] = endian.unchecked_get_u32le(k[24:28])
|
||||
ctx._s[11] = endian.unchecked_get_u32le(k[28:32])
|
||||
ctx._s[12] = 0
|
||||
if !is_xchacha {
|
||||
ctx._s[13] = util.U32_LE(n[0:4])
|
||||
ctx._s[14] = util.U32_LE(n[4:8])
|
||||
ctx._s[15] = util.U32_LE(n[8:12])
|
||||
ctx._s[13] = endian.unchecked_get_u32le(n[0:4])
|
||||
ctx._s[14] = endian.unchecked_get_u32le(n[4:8])
|
||||
ctx._s[15] = endian.unchecked_get_u32le(n[8:12])
|
||||
} else {
|
||||
ctx._s[13] = 0
|
||||
ctx._s[14] = util.U32_LE(n[0:4])
|
||||
ctx._s[15] = util.U32_LE(n[4:8])
|
||||
ctx._s[14] = endian.unchecked_get_u32le(n[0:4])
|
||||
ctx._s[15] = endian.unchecked_get_u32le(n[4:8])
|
||||
|
||||
// The sub-key is stored in the keystream buffer. While
|
||||
// this will be overwritten in most circumstances, explicitly
|
||||
@@ -179,6 +187,7 @@ reset :: proc (ctx: ^Context) {
|
||||
ctx._is_initialized = false
|
||||
}
|
||||
|
||||
@(private)
|
||||
_do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
//
|
||||
@@ -212,114 +221,114 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
}
|
||||
|
||||
x0 += _SIGMA_0
|
||||
@@ -343,93 +352,48 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// this is "use vector operations", support for that is currently
|
||||
// a work in progress/to be designed.
|
||||
//
|
||||
// Until dedicated assembly can be written leverage the fact that
|
||||
// the callers of this routine ensure that src/dst are valid.
|
||||
// In the meantime:
|
||||
// - The caller(s) ensure that src/dst are valid.
|
||||
// - The compiler knows if the target is picky about alignment.
|
||||
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
||||
// systems that also happen to not be strict about aligned
|
||||
// memory access.
|
||||
|
||||
dst_p := transmute(^[16]u32)(&dst[0])
|
||||
#no_bounds_check {
|
||||
if src != nil {
|
||||
src_p := transmute(^[16]u32)(&src[0])
|
||||
dst_p[0] = src_p[0] ~ x0
|
||||
dst_p[1] = src_p[1] ~ x1
|
||||
dst_p[2] = src_p[2] ~ x2
|
||||
dst_p[3] = src_p[3] ~ x3
|
||||
dst_p[4] = src_p[4] ~ x4
|
||||
dst_p[5] = src_p[5] ~ x5
|
||||
dst_p[6] = src_p[6] ~ x6
|
||||
dst_p[7] = src_p[7] ~ x7
|
||||
dst_p[8] = src_p[8] ~ x8
|
||||
dst_p[9] = src_p[9] ~ x9
|
||||
dst_p[10] = src_p[10] ~ x10
|
||||
dst_p[11] = src_p[11] ~ x11
|
||||
dst_p[12] = src_p[12] ~ x12
|
||||
dst_p[13] = src_p[13] ~ x13
|
||||
dst_p[14] = src_p[14] ~ x14
|
||||
dst_p[15] = src_p[15] ~ x15
|
||||
endian.unchecked_put_u32le(dst[0:4], endian.unchecked_get_u32le(src[0:4]) ~ x0)
|
||||
endian.unchecked_put_u32le(dst[4:8], endian.unchecked_get_u32le(src[4:8]) ~ x1)
|
||||
endian.unchecked_put_u32le(dst[8:12], endian.unchecked_get_u32le(src[8:12]) ~ x2)
|
||||
endian.unchecked_put_u32le(dst[12:16], endian.unchecked_get_u32le(src[12:16]) ~ x3)
|
||||
endian.unchecked_put_u32le(dst[16:20], endian.unchecked_get_u32le(src[16:20]) ~ x4)
|
||||
endian.unchecked_put_u32le(dst[20:24], endian.unchecked_get_u32le(src[20:24]) ~ x5)
|
||||
endian.unchecked_put_u32le(dst[24:28], endian.unchecked_get_u32le(src[24:28]) ~ x6)
|
||||
endian.unchecked_put_u32le(dst[28:32], endian.unchecked_get_u32le(src[28:32]) ~ x7)
|
||||
endian.unchecked_put_u32le(dst[32:36], endian.unchecked_get_u32le(src[32:36]) ~ x8)
|
||||
endian.unchecked_put_u32le(dst[36:40], endian.unchecked_get_u32le(src[36:40]) ~ x9)
|
||||
endian.unchecked_put_u32le(dst[40:44], endian.unchecked_get_u32le(src[40:44]) ~ x10)
|
||||
endian.unchecked_put_u32le(dst[44:48], endian.unchecked_get_u32le(src[44:48]) ~ x11)
|
||||
endian.unchecked_put_u32le(dst[48:52], endian.unchecked_get_u32le(src[48:52]) ~ x12)
|
||||
endian.unchecked_put_u32le(dst[52:56], endian.unchecked_get_u32le(src[52:56]) ~ x13)
|
||||
endian.unchecked_put_u32le(dst[56:60], endian.unchecked_get_u32le(src[56:60]) ~ x14)
|
||||
endian.unchecked_put_u32le(dst[60:64], endian.unchecked_get_u32le(src[60:64]) ~ x15)
|
||||
src = src[_BLOCK_SIZE:]
|
||||
} else {
|
||||
dst_p[0] = x0
|
||||
dst_p[1] = x1
|
||||
dst_p[2] = x2
|
||||
dst_p[3] = x3
|
||||
dst_p[4] = x4
|
||||
dst_p[5] = x5
|
||||
dst_p[6] = x6
|
||||
dst_p[7] = x7
|
||||
dst_p[8] = x8
|
||||
dst_p[9] = x9
|
||||
dst_p[10] = x10
|
||||
dst_p[11] = x11
|
||||
dst_p[12] = x12
|
||||
dst_p[13] = x13
|
||||
dst_p[14] = x14
|
||||
dst_p[15] = x15
|
||||
endian.unchecked_put_u32le(dst[0:4], x0)
|
||||
endian.unchecked_put_u32le(dst[4:8], x1)
|
||||
endian.unchecked_put_u32le(dst[8:12], x2)
|
||||
endian.unchecked_put_u32le(dst[12:16], x3)
|
||||
endian.unchecked_put_u32le(dst[16:20], x4)
|
||||
endian.unchecked_put_u32le(dst[20:24], x5)
|
||||
endian.unchecked_put_u32le(dst[24:28], x6)
|
||||
endian.unchecked_put_u32le(dst[28:32], x7)
|
||||
endian.unchecked_put_u32le(dst[32:36], x8)
|
||||
endian.unchecked_put_u32le(dst[36:40], x9)
|
||||
endian.unchecked_put_u32le(dst[40:44], x10)
|
||||
endian.unchecked_put_u32le(dst[44:48], x11)
|
||||
endian.unchecked_put_u32le(dst[48:52], x12)
|
||||
endian.unchecked_put_u32le(dst[52:56], x13)
|
||||
endian.unchecked_put_u32le(dst[56:60], x14)
|
||||
endian.unchecked_put_u32le(dst[60:64], x15)
|
||||
}
|
||||
dst = dst[_BLOCK_SIZE:]
|
||||
} else {
|
||||
#no_bounds_check {
|
||||
if src != nil {
|
||||
util.PUT_U32_LE(dst[0:4], util.U32_LE(src[0:4]) ~ x0)
|
||||
util.PUT_U32_LE(dst[4:8], util.U32_LE(src[4:8]) ~ x1)
|
||||
util.PUT_U32_LE(dst[8:12], util.U32_LE(src[8:12]) ~ x2)
|
||||
util.PUT_U32_LE(dst[12:16], util.U32_LE(src[12:16]) ~ x3)
|
||||
util.PUT_U32_LE(dst[16:20], util.U32_LE(src[16:20]) ~ x4)
|
||||
util.PUT_U32_LE(dst[20:24], util.U32_LE(src[20:24]) ~ x5)
|
||||
util.PUT_U32_LE(dst[24:28], util.U32_LE(src[24:28]) ~ x6)
|
||||
util.PUT_U32_LE(dst[28:32], util.U32_LE(src[28:32]) ~ x7)
|
||||
util.PUT_U32_LE(dst[32:36], util.U32_LE(src[32:36]) ~ x8)
|
||||
util.PUT_U32_LE(dst[36:40], util.U32_LE(src[36:40]) ~ x9)
|
||||
util.PUT_U32_LE(dst[40:44], util.U32_LE(src[40:44]) ~ x10)
|
||||
util.PUT_U32_LE(dst[44:48], util.U32_LE(src[44:48]) ~ x11)
|
||||
util.PUT_U32_LE(dst[48:52], util.U32_LE(src[48:52]) ~ x12)
|
||||
util.PUT_U32_LE(dst[52:56], util.U32_LE(src[52:56]) ~ x13)
|
||||
util.PUT_U32_LE(dst[56:60], util.U32_LE(src[56:60]) ~ x14)
|
||||
util.PUT_U32_LE(dst[60:64], util.U32_LE(src[60:64]) ~ x15)
|
||||
src = src[_BLOCK_SIZE:]
|
||||
} else {
|
||||
util.PUT_U32_LE(dst[0:4], x0)
|
||||
util.PUT_U32_LE(dst[4:8], x1)
|
||||
util.PUT_U32_LE(dst[8:12], x2)
|
||||
util.PUT_U32_LE(dst[12:16], x3)
|
||||
util.PUT_U32_LE(dst[16:20], x4)
|
||||
util.PUT_U32_LE(dst[20:24], x5)
|
||||
util.PUT_U32_LE(dst[24:28], x6)
|
||||
util.PUT_U32_LE(dst[28:32], x7)
|
||||
util.PUT_U32_LE(dst[32:36], x8)
|
||||
util.PUT_U32_LE(dst[36:40], x9)
|
||||
util.PUT_U32_LE(dst[40:44], x10)
|
||||
util.PUT_U32_LE(dst[44:48], x11)
|
||||
util.PUT_U32_LE(dst[48:52], x12)
|
||||
util.PUT_U32_LE(dst[52:56], x13)
|
||||
util.PUT_U32_LE(dst[56:60], x14)
|
||||
util.PUT_U32_LE(dst[60:64], x15)
|
||||
}
|
||||
dst = dst[_BLOCK_SIZE:]
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the counter. Overflow checking is done upon
|
||||
@@ -441,141 +405,142 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
}
|
||||
}
|
||||
|
||||
_hchacha20 :: proc (dst, key, nonce: []byte) {
|
||||
@(private)
|
||||
_hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
|
||||
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
|
||||
x4 := util.U32_LE(key[0:4])
|
||||
x5 := util.U32_LE(key[4:8])
|
||||
x6 := util.U32_LE(key[8:12])
|
||||
x7 := util.U32_LE(key[12:16])
|
||||
x8 := util.U32_LE(key[16:20])
|
||||
x9 := util.U32_LE(key[20:24])
|
||||
x10 := util.U32_LE(key[24:28])
|
||||
x11 := util.U32_LE(key[28:32])
|
||||
x12 := util.U32_LE(nonce[0:4])
|
||||
x13 := util.U32_LE(nonce[4:8])
|
||||
x14 := util.U32_LE(nonce[8:12])
|
||||
x15 := util.U32_LE(nonce[12:16])
|
||||
x4 := endian.unchecked_get_u32le(key[0:4])
|
||||
x5 := endian.unchecked_get_u32le(key[4:8])
|
||||
x6 := endian.unchecked_get_u32le(key[8:12])
|
||||
x7 := endian.unchecked_get_u32le(key[12:16])
|
||||
x8 := endian.unchecked_get_u32le(key[16:20])
|
||||
x9 := endian.unchecked_get_u32le(key[20:24])
|
||||
x10 := endian.unchecked_get_u32le(key[24:28])
|
||||
x11 := endian.unchecked_get_u32le(key[28:32])
|
||||
x12 := endian.unchecked_get_u32le(nonce[0:4])
|
||||
x13 := endian.unchecked_get_u32le(nonce[4:8])
|
||||
x14 := endian.unchecked_get_u32le(nonce[8:12])
|
||||
x15 := endian.unchecked_get_u32le(nonce[12:16])
|
||||
|
||||
for i := _ROUNDS; i > 0; i = i - 2 {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x0 += x4
|
||||
x12 ~= x0
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x8 += x12
|
||||
x4 ~= x8
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
|
||||
// quarterround(x, 1, 5, 9, 13)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x1 += x5
|
||||
x13 ~= x1
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x9 += x13
|
||||
x5 ~= x9
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 2, 6, 10, 14)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x2 += x6
|
||||
x14 ~= x2
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x10 += x14
|
||||
x6 ~= x10
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 3, 7, 11, 15)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x3 += x7
|
||||
x15 ~= x3
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x11 += x15
|
||||
x7 ~= x11
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 0, 5, 10, 15)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 16)
|
||||
x15 = bits.rotate_left32(x15, 16)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 12)
|
||||
x5 = bits.rotate_left32(x5, 12)
|
||||
x0 += x5
|
||||
x15 ~= x0
|
||||
x15 = util.ROTL32(x15, 8)
|
||||
x15 = bits.rotate_left32(x15, 8)
|
||||
x10 += x15
|
||||
x5 ~= x10
|
||||
x5 = util.ROTL32(x5, 7)
|
||||
x5 = bits.rotate_left32(x5, 7)
|
||||
|
||||
// quarterround(x, 1, 6, 11, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 16)
|
||||
x12 = bits.rotate_left32(x12, 16)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 12)
|
||||
x6 = bits.rotate_left32(x6, 12)
|
||||
x1 += x6
|
||||
x12 ~= x1
|
||||
x12 = util.ROTL32(x12, 8)
|
||||
x12 = bits.rotate_left32(x12, 8)
|
||||
x11 += x12
|
||||
x6 ~= x11
|
||||
x6 = util.ROTL32(x6, 7)
|
||||
x6 = bits.rotate_left32(x6, 7)
|
||||
|
||||
// quarterround(x, 2, 7, 8, 13)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 16)
|
||||
x13 = bits.rotate_left32(x13, 16)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 12)
|
||||
x7 = bits.rotate_left32(x7, 12)
|
||||
x2 += x7
|
||||
x13 ~= x2
|
||||
x13 = util.ROTL32(x13, 8)
|
||||
x13 = bits.rotate_left32(x13, 8)
|
||||
x8 += x13
|
||||
x7 ~= x8
|
||||
x7 = util.ROTL32(x7, 7)
|
||||
x7 = bits.rotate_left32(x7, 7)
|
||||
|
||||
// quarterround(x, 3, 4, 9, 14)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 16)
|
||||
x14 = bits.rotate_left32(x14, 16)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 12)
|
||||
x4 = bits.rotate_left32(x4, 12)
|
||||
x3 += x4
|
||||
x14 ~= x3
|
||||
x14 = util.ROTL32(x14, 8)
|
||||
x14 = bits.rotate_left32(x14, 8)
|
||||
x9 += x14
|
||||
x4 ~= x9
|
||||
x4 = util.ROTL32(x4, 7)
|
||||
x4 = bits.rotate_left32(x4, 7)
|
||||
}
|
||||
|
||||
util.PUT_U32_LE(dst[0:4], x0)
|
||||
util.PUT_U32_LE(dst[4:8], x1)
|
||||
util.PUT_U32_LE(dst[8:12], x2)
|
||||
util.PUT_U32_LE(dst[12:16], x3)
|
||||
util.PUT_U32_LE(dst[16:20], x12)
|
||||
util.PUT_U32_LE(dst[20:24], x13)
|
||||
util.PUT_U32_LE(dst[24:28], x14)
|
||||
util.PUT_U32_LE(dst[28:32], x15)
|
||||
endian.unchecked_put_u32le(dst[0:4], x0)
|
||||
endian.unchecked_put_u32le(dst[4:8], x1)
|
||||
endian.unchecked_put_u32le(dst[8:12], x2)
|
||||
endian.unchecked_put_u32le(dst[12:16], x3)
|
||||
endian.unchecked_put_u32le(dst[16:20], x12)
|
||||
endian.unchecked_put_u32le(dst[20:24], x13)
|
||||
endian.unchecked_put_u32le(dst[24:28], x14)
|
||||
endian.unchecked_put_u32le(dst[28:32], x15)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user