mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-07 12:11:36 -07:00
Compare commits
630 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fcc920ed39 | |||
| 4e70256109 | |||
| 2e4d6d2577 | |||
| 51ae21a029 | |||
| f59846377d | |||
| 8e8eb9e5cd | |||
| 88b578ca11 | |||
| 4cb16db4e9 | |||
| 338d483682 | |||
| 0ce59a9e2b | |||
| 8d43cc840a | |||
| 9ae1bfb69d | |||
| 6ec7284467 | |||
| 0ccc570ef2 | |||
| a3bb7d3028 | |||
| c45ca1bfcc | |||
| 94edf89b20 | |||
| 8d6ce0b693 | |||
| ccf4b48865 | |||
| 96eae94103 | |||
| db8b2e69dd | |||
| 82821580c7 | |||
| d23d7cf0f2 | |||
| 450a602230 | |||
| 36764779cf | |||
| 97595c4b50 | |||
| ea9fe397e5 | |||
| c482432966 | |||
| 55176e52fc | |||
| 4eb08bb096 | |||
| 881ef69063 | |||
| 761a19689d | |||
| f438153b81 | |||
| 117c0cceb1 | |||
| c949e404c3 | |||
| 3d2a6c5895 | |||
| 8f4ffbe1da | |||
| 8f3b6738ff | |||
| d50c6d72db | |||
| 15c5e92d63 | |||
| 041c7c8284 | |||
| f040ef41cb | |||
| 91ab184175 | |||
| 48a64a2c88 | |||
| 7f3795a231 | |||
| eb1d00ced6 | |||
| f41c91d36b | |||
| 6909e0d774 | |||
| d52921edd4 | |||
| dcca40033e | |||
| fed65742df | |||
| b918acd871 | |||
| a046c41c7c | |||
| 2513403014 | |||
| 4a8564aff7 | |||
| edb23db2ae | |||
| 0b01cfd853 | |||
| 0d059aa797 | |||
| 65c0255e7e | |||
| b289a27c4e | |||
| d085283f20 | |||
| b6ca10cd5e | |||
| 7416f72565 | |||
| b51be71a6f | |||
| e488cf4601 | |||
| 5d397804f7 | |||
| a5a7226885 | |||
| 2dca39b557 | |||
| b55fa268bf | |||
| c819c350d6 | |||
| d55248ab0f | |||
| 68b2d4b9e2 | |||
| 54f02f59db | |||
| 64047cbf05 | |||
| b0619980b2 | |||
| 9aa9429135 | |||
| 518f30e523 | |||
| 868aa4c14a | |||
| 1ab90de493 | |||
| 1064bcd060 | |||
| 1e21125527 | |||
| 4a8c37dd52 | |||
| 3b22c6620c | |||
| 402a165b60 | |||
| 34f9170189 | |||
| 38136e15fc | |||
| e97bf2ef35 | |||
| d6c54148d9 | |||
| cbe3791b42 | |||
| b470ceb470 | |||
| c15db05199 | |||
| 9428f792ed | |||
| 520ff731de | |||
| e9cfe698ba | |||
| 5fa66ac6a8 | |||
| 320062157f | |||
| d7d6608142 | |||
| 7f2ef2ac67 | |||
| 7124d541a1 | |||
| 3c7e45a46f | |||
| 6ec014e980 | |||
| 9b47a5eddb | |||
| 3e8c63ad31 | |||
| 15469758de | |||
| 86511d44e4 | |||
| fd4633eb25 | |||
| b0756f9e29 | |||
| c3ff1e9591 | |||
| dd3fac7523 | |||
| 13029d06b2 | |||
| 68173f4bc7 | |||
| c979c2fafa | |||
| 658435f1b9 | |||
| 3935957979 | |||
| a36640bcfc | |||
| 171d5b4012 | |||
| 1cc893f21c | |||
| 6ff2db47b4 | |||
| a11b6a9e5f | |||
| 978568684c | |||
| e8e7d3ea31 | |||
| c03cc21908 | |||
| 8ef406324b | |||
| 23d0c52bf4 | |||
| 5eee8077dd | |||
| 029cb6581b | |||
| 025e87d974 | |||
| 213a0499a1 | |||
| 1517f1d779 | |||
| 50a2493fd3 | |||
| b455ccd261 | |||
| a58650728e | |||
| b22ddb1453 | |||
| cb7dd12222 | |||
| 0484bdbb7e | |||
| 8f39c45e9b | |||
| 944396128b | |||
| bbb2164e38 | |||
| be23d83fc8 | |||
| 291ea33939 | |||
| 9455918eec | |||
| 8a99b8af3e | |||
| 12e42d92d3 | |||
| faa735d0c7 | |||
| d4e18109da | |||
| d06a0e7093 | |||
| b3a55b8b6f | |||
| ec69101101 | |||
| 17fa8cb6ef | |||
| 855ebceadc | |||
| 2720e98127 | |||
| bb80c1b059 | |||
| 85e390deba | |||
| dc317c8cd8 | |||
| 774fea1e63 | |||
| 485c606672 | |||
| 3dee3205b2 | |||
| c7a704d345 | |||
| 0fb3032b73 | |||
| 69934c3b0b | |||
| 7380b7e61b | |||
| 747a11a954 | |||
| 252be0fb41 | |||
| 600f2b7284 | |||
| 670274ad8f | |||
| e10fe91eba | |||
| fd62ee14cd | |||
| 8ece92f1f6 | |||
| 69b075782b | |||
| 6bd3a9d422 | |||
| bc9ee8e1a4 | |||
| d36c3c2590 | |||
| 52b319dbfd | |||
| 318d92f9a8 | |||
| 7ffffeeccc | |||
| f16d8e77b3 | |||
| 5b335bb88c | |||
| df2767311f | |||
| 09c26e6be0 | |||
| d2ec2d1606 | |||
| 0d87b2e8db | |||
| 1568971732 | |||
| 0e040be941 | |||
| 9737b65d9c | |||
| ad52003077 | |||
| c386509112 | |||
| c293f5b7eb | |||
| fa562ec5d6 | |||
| 529383f5b1 | |||
| f01cff7ff0 | |||
| 015fe924b8 | |||
| a5ce8a8c0b | |||
| bfdcf900ef | |||
| 54f89dd84b | |||
| da479c7628 | |||
| 3c90a05957 | |||
| d16ddf7926 | |||
| 5c519f0e8d | |||
| 74e6d9144e | |||
| 20d451396d | |||
| 60d0390ef8 | |||
| 782f1b4718 | |||
| 85f0a1067c | |||
| c08ff891ad | |||
| 168cec1e9d | |||
| 28fb35f2f7 | |||
| c1384afe2f | |||
| 547c7bce1b | |||
| 0bb93d40d3 | |||
| 27ba1d596c | |||
| 98e5523f2f | |||
| 223b66f422 | |||
| 04a4dbcdaf | |||
| ef9e31cb31 | |||
| e019673a18 | |||
| 5f27f2dd7f | |||
| cfccf73cdd | |||
| 465d003b1e | |||
| 1d6f7680a1 | |||
| 5d0f9c428a | |||
| d904ae5191 | |||
| 8a822bdd9a | |||
| d1a3842e39 | |||
| 00823ca88c | |||
| ffa14c3aad | |||
| 41b32f0da4 | |||
| c53b2198a8 | |||
| 9b278db993 | |||
| e98f1a28e6 | |||
| c8f05b7c0c | |||
| b00c4a6a8f | |||
| 84e1fb2cee | |||
| b983ac548c | |||
| fb562ea708 | |||
| cdeeeafc3f | |||
| b9a2426e57 | |||
| 81037b3091 | |||
| fc3c76f946 | |||
| 3fa971a510 | |||
| 63a0395a79 | |||
| 191223bb3c | |||
| 6f0bad816e | |||
| 94af3c2887 | |||
| e5d0417a6c | |||
| c02bda2427 | |||
| 385d2a143c | |||
| 67c1b364c4 | |||
| f029b4beb1 | |||
| 3040361fac | |||
| 44caa96d50 | |||
| 1bea0f3772 | |||
| eb0775ad53 | |||
| 8fc9566a83 | |||
| 134c7db4d2 | |||
| a0e3a99dd1 | |||
| 0edda2bea7 | |||
| ff7f139fd7 | |||
| 86a606e716 | |||
| 1e97588e7b | |||
| 3ccc0b5aa6 | |||
| 5464a605b1 | |||
| 5519749aa4 | |||
| 4a70265bfb | |||
| de0d860880 | |||
| a13e2f4578 | |||
| 01b508f182 | |||
| 2a8fa8612d | |||
| e27046098b | |||
| ca8b148fdc | |||
| c1f5be24e2 | |||
| 6cdec65ca1 | |||
| 967afd8bbb | |||
| 0ae1812f90 | |||
| eb5523d5d3 | |||
| 3f4bbbec29 | |||
| 70bd220f34 | |||
| bd3596f012 | |||
| 66ce990e0b | |||
| 690666537c | |||
| 056ba1ed13 | |||
| 93a1f2bf61 | |||
| ac5f5a33e9 | |||
| 0829ac30f7 | |||
| 9d50a04905 | |||
| 1ca7da6914 | |||
| 56e050fbc9 | |||
| 70e48e39a4 | |||
| 2b0c04f27e | |||
| 1ddbe16d28 | |||
| 09c1128d9e | |||
| 588c52a854 | |||
| 86ec3bcb44 | |||
| 9fc606de48 | |||
| 7fbee88061 | |||
| b3be2cdf9d | |||
| ff6b76986a | |||
| 5c3624eb86 | |||
| 144e357fd2 | |||
| be22f0d1e1 | |||
| 34a048f7da | |||
| ffe953b43d | |||
| b8eacfc7b6 | |||
| f8452bf1fc | |||
| 20943a81c1 | |||
| 1c4e75e83f | |||
| 9cb9964c2d | |||
| 1f8f94276e | |||
| 0d7c89e84a | |||
| a5bdb4a8e8 | |||
| 521ed28632 | |||
| d6300314c0 | |||
| 27130259cc | |||
| b4fb295bb3 | |||
| f7e608628b | |||
| 605d66845a | |||
| 37ec3d7006 | |||
| 89eb351d2b | |||
| abaacfe78d | |||
| f9f4551e8d | |||
| daf005d1ab | |||
| ce1ee962f5 | |||
| d0e4edfb43 | |||
| 749e5067fb | |||
| 75dcaf6d8d | |||
| 00a0a1e95d | |||
| 7a4106077a | |||
| 9c8eaeb988 | |||
| 7ed28e8a84 | |||
| a3d53a6288 | |||
| 2127dc56b1 | |||
| e59e34d334 | |||
| 4fd97c3ba6 | |||
| 107c7a36d0 | |||
| dcf2c43863 | |||
| 0c25f7cdc5 | |||
| e5c243ee93 | |||
| e9b6a8fc9a | |||
| a27c00862c | |||
| a06f75b6fb | |||
| d88b052d2d | |||
| 615eccb6d1 | |||
| d3c65b6ba5 | |||
| 90415e4a6e | |||
| 7352c312e0 | |||
| 0befadde1d | |||
| aef8b25a8e | |||
| ae81117f70 | |||
| d6cb105d5f | |||
| b7b9a016d3 | |||
| 5ac36b5f25 | |||
| 22bcf1ba70 | |||
| 51c705edf1 | |||
| 708a1b0cd3 | |||
| 7ab591667a | |||
| e45401bfb4 | |||
| 6b652afb8e | |||
| 0a0db23b17 | |||
| 76b85c0622 | |||
| 6fa0679be9 | |||
| afea221d64 | |||
| b9ec2de4db | |||
| 3dfd53aee0 | |||
| b54fc8ff95 | |||
| 8745942255 | |||
| c7be30e0ea | |||
| 1baa47c78e | |||
| 0b33df4e9d | |||
| 4c40495742 | |||
| 824b97d250 | |||
| 5bbab05161 | |||
| 83558a1352 | |||
| cb183e968a | |||
| 27d56d0da4 | |||
| c663566cd5 | |||
| 13d052027f | |||
| 7076cf69e4 | |||
| 6ae8adaa45 | |||
| 15bbdb2030 | |||
| 48c9c1682c | |||
| d3c5143292 | |||
| 3949e2220f | |||
| 9ed4f95c1a | |||
| 8daecf7532 | |||
| 11d665c25a | |||
| 98a086b91b | |||
| f323a179d9 | |||
| c6f282d20b | |||
| ba49a9100d | |||
| 6fe77155b5 | |||
| 677e7ff642 | |||
| 682b5fa0d3 | |||
| ab00db2ebd | |||
| 0a0e8f36eb | |||
| bbe44b49bc | |||
| 25bec19b1f | |||
| 81f83d5780 | |||
| d2019e3e4d | |||
| 489e8dc592 | |||
| 3edb3d8d8c | |||
| a705a2e38b | |||
| 7dfbda58d9 | |||
| 9b88a38e54 | |||
| 16a494347c | |||
| ad0f11668b | |||
| 699cabeb1c | |||
| 7207f4b0c5 | |||
| 9c1b464c94 | |||
| 04a1e7d638 | |||
| 7cfbd87f57 | |||
| e9e05a3783 | |||
| 2b83f27f06 | |||
| 3d0e194298 | |||
| fcd8860990 | |||
| 22840ddf97 | |||
| f9576c2f5b | |||
| 16fc961010 | |||
| d2701d8b13 | |||
| a0bd31646b | |||
| 0d37da54b4 | |||
| 5d47e2a166 | |||
| 035c75d6a9 | |||
| b475481788 | |||
| 033525fe13 | |||
| 8852d090b6 | |||
| ac259ac790 | |||
| 7b4a87d37c | |||
| f6fc3ebe37 | |||
| 5c106abe3f | |||
| db748b7a05 | |||
| f2f2d532f5 | |||
| 1bcec3f769 | |||
| b035ee2bcd | |||
| 0424fb486b | |||
| 3858422f1d | |||
| d4f343751e | |||
| 79baddc157 | |||
| bcf437dc11 | |||
| 503eb470a7 | |||
| 667af1be58 | |||
| 366779f8c7 | |||
| dae299b781 | |||
| 2f29894b45 | |||
| 0819d05a0b | |||
| 6a4e44607c | |||
| a71daee545 | |||
| 046dd55032 | |||
| 2fc3da3fde | |||
| a74093784c | |||
| ed58374964 | |||
| 6dd4d1a924 | |||
| d77269dee2 | |||
| ea263b8cc5 | |||
| 45f0c812af | |||
| 810a1eee41 | |||
| e3e225d21b | |||
| 50e10ceb3b | |||
| da774e3fd2 | |||
| 2c3febd620 | |||
| bce62b98d4 | |||
| e914a8710d | |||
| c96e0afbf1 | |||
| f1c24f434b | |||
| e8517e1d02 | |||
| 92e406cef0 | |||
| 269913ede0 | |||
| 2ed16240a7 | |||
| ff36b754cb | |||
| 503b897677 | |||
| d69c74665a | |||
| fcf081283c | |||
| 7a6e8543a6 | |||
| f30755a871 | |||
| 503220e4c1 | |||
| 051814a69c | |||
| 21843da9e3 | |||
| 30f49f81c1 | |||
| 439f4776e4 | |||
| b743f56fb9 | |||
| 1fc3f6cb2e | |||
| df19c48da8 | |||
| f7211408fc | |||
| 30db316e16 | |||
| 8c01e952f3 | |||
| 3e66b88031 | |||
| f76316f889 | |||
| 32477a88ef | |||
| e8bc576b23 | |||
| 2eea6f2490 | |||
| 1d9d79542c | |||
| 1a6d4c955a | |||
| 717522efe4 | |||
| 8d06d9c23d | |||
| 765c1546c5 | |||
| 7ec6fd30f0 | |||
| 0ca773114a | |||
| 9e1576418f | |||
| b7ea169c81 | |||
| 3b583cbac7 | |||
| 382bd87667 | |||
| 6cc07dc24e | |||
| 01cdd22a01 | |||
| 35331e6973 | |||
| c18e98e8c5 | |||
| 3cd553565f | |||
| 9eec9f5788 | |||
| 2b7ca2bdd6 | |||
| 411c0add3b | |||
| 18d7ecc1a5 | |||
| 4812601e78 | |||
| 2d5779b660 | |||
| fd53e8b955 | |||
| 53a030c65b | |||
| 91ad6b42c5 | |||
| dad10ef800 | |||
| 71eb21aab7 | |||
| f8228e305a | |||
| 0e7109cab2 | |||
| c39ef1b25c | |||
| 9da37ed394 | |||
| 8fa571c283 | |||
| 83f3ae14d5 | |||
| 6a14c3edb4 | |||
| 2cd895c50b | |||
| ee89c0458f | |||
| cee847a68c | |||
| 413f96553a | |||
| 662ed4a67c | |||
| 85a263130d | |||
| d19ae37af1 | |||
| 22672a816e | |||
| dcb873c88d | |||
| 62ab2987b6 | |||
| 7bcde35651 | |||
| 4b8721a0bb | |||
| 7743e34596 | |||
| 4003b76fd3 | |||
| c27ed1896f | |||
| 7d217269b5 | |||
| a3c8882648 | |||
| 4389059834 | |||
| a55e90fefd | |||
| f58f922487 | |||
| 1a0930f841 | |||
| a5f8c3f692 | |||
| 92fb65cf2e | |||
| a51943e27f | |||
| 03c834e410 | |||
| 989107094c | |||
| fd8956b8f4 | |||
| 648e3c65ea | |||
| d5047e621d | |||
| 8fbdef01d6 | |||
| 9dee943fae | |||
| 8ceb691cec | |||
| f26516f6fa | |||
| fda8e8a30b | |||
| 2242178d96 | |||
| a459bc13dc | |||
| 53e84b7f31 | |||
| 098f51aa80 | |||
| 765969e6a3 | |||
| 8086c14dcc | |||
| 80ce1b7d85 | |||
| 9f55404845 | |||
| 075040ae05 | |||
| aa799d6a0d | |||
| 58e607e960 | |||
| ff51c5ee56 | |||
| 73c1f08776 | |||
| 412ca36230 | |||
| 06d1df4cae | |||
| 7662808bc9 | |||
| d48828dd80 | |||
| b725e01cdd | |||
| 874c1f076d | |||
| 2c14f0a109 | |||
| cf4afc2e7b | |||
| 5ed06f7eb8 | |||
| 765cd66b30 | |||
| 5a8fbc230d | |||
| 5c62211f00 | |||
| 835b8ffa22 | |||
| b84108c4b5 | |||
| 6642e1fc9d | |||
| c909e8e4b8 | |||
| 9bdbb45517 | |||
| 1b5860e574 | |||
| 047d45584e | |||
| 721486f875 | |||
| 29f2ecd228 | |||
| 970ac22647 | |||
| 419eab5059 | |||
| a1935bc1f4 | |||
| fc06c8ed9f | |||
| 7952b26e8b | |||
| fa6cfde4b0 | |||
| 4c78ba2152 | |||
| 9870e43ac0 | |||
| 63086c7eaf | |||
| ef0c6fc4b3 | |||
| 159c5311c3 | |||
| b6a65fac36 | |||
| ab7367ae47 | |||
| 457f509b5f | |||
| 7e5c063d98 | |||
| dfabd0e0ad | |||
| 141133e326 | |||
| e188a542da | |||
| 64f1e8b7a2 | |||
| 62440df051 | |||
| 5362e883f4 | |||
| 8b06fd0935 | |||
| bb9b58b8c4 | |||
| ee070c9bd3 | |||
| aebafdcd08 | |||
| 2b4fce8684 | |||
| de8f6709f7 | |||
| 683753db96 | |||
| d13dc7eca7 | |||
| e56920e445 | |||
| 1c9aad4d7b | |||
| ce09cb0bdb | |||
| b7fd91817e | |||
| a728047281 | |||
| 5cf473b31c | |||
| c767d55e9a | |||
| 7f601c9535 | |||
| e139d1cbe4 | |||
| cb04116caf | |||
| 62ff8daa78 |
+15
-10
@@ -38,6 +38,11 @@ jobs:
|
|||||||
cd tests/vendor
|
cd tests/vendor
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin internals tests
|
||||||
|
run: |
|
||||||
|
cd tests/internal
|
||||||
|
make
|
||||||
|
timeout-minutes: 10
|
||||||
- name: Odin check examples/all for Linux i386
|
- name: Odin check examples/all for Linux i386
|
||||||
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
@@ -87,10 +92,10 @@ jobs:
|
|||||||
cd tests/vendor
|
cd tests/vendor
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin issues tests
|
- name: Odin internals tests
|
||||||
run: |
|
run: |
|
||||||
cd tests/issues
|
cd tests/internal
|
||||||
./run.sh
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin check examples/all for Darwin arm64
|
- name: Odin check examples/all for Darwin arm64
|
||||||
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
|
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
|
||||||
@@ -151,6 +156,13 @@ jobs:
|
|||||||
cd tests\vendor
|
cd tests\vendor
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
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
|
||||||
|
cd tests\internal
|
||||||
|
call build.bat
|
||||||
|
timeout-minutes: 10
|
||||||
- name: core:math/big tests
|
- name: core:math/big tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
@@ -158,13 +170,6 @@ jobs:
|
|||||||
cd tests\core\math\big
|
cd tests\core\math\big
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: Odin issues tests
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
|
||||||
cd tests\issues
|
|
||||||
call run.bat
|
|
||||||
timeout-minutes: 10
|
|
||||||
- name: Odin check examples/all for Windows 32bits
|
- name: Odin check examples/all for Windows 32bits
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Close Stale Issues
|
- name: Close Stale Issues
|
||||||
uses: actions/stale@v4.1.0
|
uses: actions/stale@v7.0.0
|
||||||
with:
|
with:
|
||||||
# stale-issue-message: |
|
# stale-issue-message: |
|
||||||
# Hello!
|
# Hello!
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||||
|
|
||||||
days-before-stale: 120
|
days-before-stale: 120
|
||||||
days-before-close: 30
|
days-before-close: -1
|
||||||
exempt-draft-pr: true
|
exempt-draft-pr: true
|
||||||
ascending: true
|
ascending: true
|
||||||
operations-per-run: 1000
|
operations-per-run: 1000
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ A wiki maintained by the Odin community.
|
|||||||
|
|
||||||
#### [Odin Discord](https://discord.gg/sVBPHEv)
|
#### [Odin Discord](https://discord.gg/sVBPHEv)
|
||||||
|
|
||||||
Get live support and talk with other odiners on the Odin Discord.
|
Get live support and talk with other Odin programmers on the Odin Discord.
|
||||||
|
|
||||||
### Articles
|
### Articles
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,21 @@
|
|||||||
|
|
||||||
setlocal EnableDelayedExpansion
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (
|
for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (
|
||||||
set CURR_DATE_TIME=%%j
|
set CURR_DATE_TIME=%%j
|
||||||
)
|
)
|
||||||
@@ -47,12 +62,14 @@ if %release_mode% EQU 0 ( rem Debug
|
|||||||
set compiler_warnings= ^
|
set compiler_warnings= ^
|
||||||
-W4 -WX ^
|
-W4 -WX ^
|
||||||
-wd4100 -wd4101 -wd4127 -wd4146 ^
|
-wd4100 -wd4101 -wd4127 -wd4146 ^
|
||||||
|
-wd4505 ^
|
||||||
-wd4456 -wd4457
|
-wd4456 -wd4457
|
||||||
|
|
||||||
set compiler_includes= ^
|
set compiler_includes= ^
|
||||||
/Isrc\
|
/Isrc\
|
||||||
set libs= ^
|
set libs= ^
|
||||||
kernel32.lib ^
|
kernel32.lib ^
|
||||||
|
Synchronization.lib ^
|
||||||
bin\llvm\windows\LLVM-C.lib
|
bin\llvm\windows\LLVM-C.lib
|
||||||
|
|
||||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||||
@@ -79,4 +96,4 @@ if %release_mode% EQU 0 odin run examples/demo
|
|||||||
|
|
||||||
del *.obj > NUL 2> NUL
|
del *.obj > NUL 2> NUL
|
||||||
|
|
||||||
:end_of_build
|
:end_of_build
|
||||||
|
|||||||
+21
-1
@@ -44,7 +44,13 @@ config_darwin() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
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 -liconv -ldl -framework System"
|
||||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||||
}
|
}
|
||||||
@@ -97,6 +103,12 @@ config_linux() {
|
|||||||
panic "Requirement: llvm-config must be base version greater than 11"
|
panic "Requirement: llvm-config must be base version greater than 11"
|
||||||
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
|
||||||
|
|
||||||
LDFLAGS="$LDFLAGS -ldl"
|
LDFLAGS="$LDFLAGS -ldl"
|
||||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs --libfiles) -Wl,-rpath=\$ORIGIN"
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs --libfiles) -Wl,-rpath=\$ORIGIN"
|
||||||
@@ -134,6 +146,14 @@ run_demo() {
|
|||||||
./odin run examples/demo/demo.odin -file
|
./odin run examples/demo/demo.odin -file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
have_which() {
|
||||||
|
if ! which which > /dev/null 2>&1; then
|
||||||
|
panic "Could not find \`which\`"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
have_which
|
||||||
|
|
||||||
case $OS in
|
case $OS in
|
||||||
Linux)
|
Linux)
|
||||||
config_linux
|
config_linux
|
||||||
|
|||||||
@@ -15,3 +15,10 @@ if not exist "vendor\miniaudio\lib\*.lib" (
|
|||||||
call build.bat
|
call build.bat
|
||||||
popd
|
popd
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if not exist "vendor\cgltf\lib\*.lib" (
|
||||||
|
pushd vendor\cgltf\src
|
||||||
|
call build.bat
|
||||||
|
popd
|
||||||
|
)
|
||||||
|
|||||||
+15
-2
@@ -14,11 +14,24 @@ when ODIN_OS == .Windows {
|
|||||||
// EDOM,
|
// EDOM,
|
||||||
// EILSEQ
|
// EILSEQ
|
||||||
// ERANGE
|
// ERANGE
|
||||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
when ODIN_OS == .Linux {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@(link_name="__libc_errno_location")
|
@(link_name="__errno_location")
|
||||||
|
_get_errno :: proc() -> ^int ---
|
||||||
|
}
|
||||||
|
|
||||||
|
EDOM :: 33
|
||||||
|
EILSEQ :: 84
|
||||||
|
ERANGE :: 34
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .FreeBSD {
|
||||||
|
@(private="file")
|
||||||
|
@(default_calling_convention="c")
|
||||||
|
foreign libc {
|
||||||
|
@(link_name="__error")
|
||||||
_get_errno :: proc() -> ^int ---
|
_get_errno :: proc() -> ^int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ when ODIN_OS == .Linux {
|
|||||||
cnd_destroy :: proc(cond: ^cnd_t) ---
|
cnd_destroy :: proc(cond: ^cnd_t) ---
|
||||||
cnd_init :: proc(cond: ^cnd_t) -> int ---
|
cnd_init :: proc(cond: ^cnd_t) -> int ---
|
||||||
cnd_signal :: proc(cond: ^cnd_t) -> int ---
|
cnd_signal :: proc(cond: ^cnd_t) -> int ---
|
||||||
cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
|
cnd_timedwait :: proc(cond: ^cnd_t, mtx: ^mtx_t, ts: ^timespec) -> int ---
|
||||||
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
||||||
|
|
||||||
// 7.26.4 Mutex functions
|
// 7.26.4 Mutex functions
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//+ignore
|
//+build ignore
|
||||||
package gzip
|
package gzip
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//+ignore
|
//+build ignore
|
||||||
package zlib
|
package zlib
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package container_small_array
|
package container_small_array
|
||||||
|
|
||||||
import "core:builtin"
|
import "core:builtin"
|
||||||
|
import "core:runtime"
|
||||||
|
_ :: runtime
|
||||||
|
|
||||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||||
data: [N]T,
|
data: [N]T,
|
||||||
@@ -8,40 +10,54 @@ Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
len :: proc(a: $A/Small_Array) -> int {
|
len :: proc "contextless" (a: $A/Small_Array) -> int {
|
||||||
return a.len
|
return a.len
|
||||||
}
|
}
|
||||||
|
|
||||||
cap :: proc(a: $A/Small_Array) -> int {
|
cap :: proc "contextless" (a: $A/Small_Array) -> int {
|
||||||
return builtin.len(a.data)
|
return builtin.len(a.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
space :: proc(a: $A/Small_Array) -> int {
|
space :: proc "contextless" (a: $A/Small_Array) -> int {
|
||||||
return builtin.len(a.data) - a.len
|
return builtin.len(a.data) - a.len
|
||||||
}
|
}
|
||||||
|
|
||||||
slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
|
slice :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> []T {
|
||||||
return a.data[:a.len]
|
return a.data[:a.len]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get :: proc(a: $A/Small_Array($N, $T), index: int) -> T {
|
get :: proc "contextless" (a: $A/Small_Array($N, $T), index: int) -> T {
|
||||||
return a.data[index]
|
return a.data[index]
|
||||||
}
|
}
|
||||||
get_ptr :: proc(a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
get_ptr :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
||||||
return &a.data[index]
|
return &a.data[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
|
||||||
|
if index < 0 || index >= a.len {
|
||||||
|
return {}, false
|
||||||
|
}
|
||||||
|
return a.data[index], true
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
|
||||||
|
if index < 0 || index >= a.len {
|
||||||
|
return {}, false
|
||||||
|
}
|
||||||
|
return &a.data[index], true
|
||||||
|
}
|
||||||
|
|
||||||
|
set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||||
a.data[index] = item
|
a.data[index] = item
|
||||||
}
|
}
|
||||||
|
|
||||||
resize :: proc(a: ^$A/Small_Array, length: int) {
|
resize :: proc "contextless" (a: ^$A/Small_Array, length: int) {
|
||||||
a.len = min(length, builtin.len(a.data))
|
a.len = min(length, builtin.len(a.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
push_back :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||||
if a.len < cap(a^) {
|
if a.len < cap(a^) {
|
||||||
a.data[a.len] = item
|
a.data[a.len] = item
|
||||||
a.len += 1
|
a.len += 1
|
||||||
@@ -50,7 +66,7 @@ push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
push_front :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
||||||
if a.len < cap(a^) {
|
if a.len < cap(a^) {
|
||||||
a.len += 1
|
a.len += 1
|
||||||
data := slice(a)
|
data := slice(a)
|
||||||
@@ -61,14 +77,14 @@ push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
pop_back :: proc "odin" (a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||||
assert(condition=(N > 0 && a.len > 0), loc=loc)
|
assert(condition=(N > 0 && a.len > 0), loc=loc)
|
||||||
item := a.data[a.len-1]
|
item := a.data[a.len-1]
|
||||||
a.len -= 1
|
a.len -= 1
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
pop_front :: proc "odin" (a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
||||||
assert(condition=(N > 0 && a.len > 0), loc=loc)
|
assert(condition=(N > 0 && a.len > 0), loc=loc)
|
||||||
item := a.data[0]
|
item := a.data[0]
|
||||||
s := slice(a)
|
s := slice(a)
|
||||||
@@ -77,7 +93,7 @@ pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
|
|||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
pop_back_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||||
if N > 0 && a.len > 0 {
|
if N > 0 && a.len > 0 {
|
||||||
item = a.data[a.len-1]
|
item = a.data[a.len-1]
|
||||||
a.len -= 1
|
a.len -= 1
|
||||||
@@ -86,31 +102,60 @@ pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
pop_front_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
|
||||||
if N > 0 && a.len > 0 {
|
if N > 0 && a.len > 0 {
|
||||||
item = a.data[0]
|
item = a.data[0]
|
||||||
s := slice(a)
|
s := slice(a)
|
||||||
copy(s[:], s[1:])
|
copy(s[:], s[1:])
|
||||||
a.len -= 1
|
a.len -= 1
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) {
|
consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) {
|
||||||
assert(condition=a.len >= count, loc=loc)
|
assert(condition=a.len >= count, loc=loc)
|
||||||
a.len -= count
|
a.len -= count
|
||||||
}
|
}
|
||||||
|
|
||||||
clear :: proc(a: ^$A/Small_Array($N, $T)) {
|
ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
|
||||||
|
runtime.bounds_check_error_loc(loc, index, a.len)
|
||||||
|
if index+1 < a.len {
|
||||||
|
copy(a.data[index:], a.data[index+1:])
|
||||||
|
}
|
||||||
|
a.len -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
|
||||||
|
runtime.bounds_check_error_loc(loc, index, a.len)
|
||||||
|
n := a.len-1
|
||||||
|
if index != n {
|
||||||
|
a.data[index] = a.data[n]
|
||||||
|
}
|
||||||
|
a.len -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
|
||||||
resize(a, 0)
|
resize(a, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
|
push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||||
n := copy(a.data[a.len:], items[:])
|
n := copy(a.data[a.len:], items[:])
|
||||||
a.len += n
|
a.len += n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check {
|
||||||
|
if a.len < cap(a^) && index >= 0 && index <= len(a^) {
|
||||||
|
a.len += 1
|
||||||
|
for i := a.len - 1; i >= index + 1; i -= 1 {
|
||||||
|
a.data[i] = a.data[i - 1]
|
||||||
|
}
|
||||||
|
a.data[index] = item
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
append_elem :: push_back
|
append_elem :: push_back
|
||||||
append_elems :: push_back_elems
|
append_elems :: push_back_elems
|
||||||
push :: proc{push_back, push_back_elems}
|
push :: proc{push_back, push_back_elems}
|
||||||
|
|||||||
@@ -257,21 +257,22 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
|||||||
opt_write_start(w, opt, '{') or_return
|
opt_write_start(w, opt, '{') or_return
|
||||||
|
|
||||||
if m != nil {
|
if m != nil {
|
||||||
if info.generated_struct == nil {
|
if info.map_info == nil {
|
||||||
return .Unsupported_Type
|
return .Unsupported_Type
|
||||||
}
|
}
|
||||||
entries := &m.entries
|
map_cap := uintptr(runtime.map_cap(m^))
|
||||||
gs := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct)
|
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
|
||||||
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
|
|
||||||
entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
|
|
||||||
entry_size := ed.elem_size
|
|
||||||
|
|
||||||
for i in 0..<entries.len {
|
i := 0
|
||||||
|
for bucket_index in 0..<map_cap {
|
||||||
|
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
opt_write_iteration(w, opt, i) or_return
|
opt_write_iteration(w, opt, i) or_return
|
||||||
|
i += 1
|
||||||
|
|
||||||
data := uintptr(entries.data) + uintptr(i*entry_size)
|
key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
|
||||||
key := rawptr(data + entry_type.offsets[2])
|
value := rawptr(runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index))
|
||||||
value := rawptr(data + entry_type.offsets[3])
|
|
||||||
|
|
||||||
// check for string type
|
// check for string type
|
||||||
{
|
{
|
||||||
@@ -281,13 +282,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
|||||||
name: string
|
name: string
|
||||||
|
|
||||||
#partial switch info in ti.variant {
|
#partial switch info in ti.variant {
|
||||||
case runtime.Type_Info_String:
|
case runtime.Type_Info_String:
|
||||||
switch s in a {
|
switch s in a {
|
||||||
case string: name = s
|
case string: name = s
|
||||||
case cstring: name = string(s)
|
case cstring: name = string(s)
|
||||||
}
|
}
|
||||||
opt_write_key(w, opt, name) or_return
|
opt_write_key(w, opt, name) or_return
|
||||||
|
|
||||||
case: return .Unsupported_Type
|
case: return .Unsupported_Type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -399,12 +399,10 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
return UNSUPPORTED_TYPE
|
return UNSUPPORTED_TYPE
|
||||||
}
|
}
|
||||||
raw_map := (^mem.Raw_Map)(v.data)
|
raw_map := (^mem.Raw_Map)(v.data)
|
||||||
if raw_map.entries.allocator.procedure == nil {
|
if raw_map.allocator.procedure == nil {
|
||||||
raw_map.entries.allocator = p.allocator
|
raw_map.allocator = p.allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
header := runtime.__get_map_header_table_runtime(t)
|
|
||||||
|
|
||||||
elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
|
elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
|
||||||
defer delete(elem_backing, p.allocator)
|
defer delete(elem_backing, p.allocator)
|
||||||
|
|
||||||
@@ -421,7 +419,6 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
key_hash := runtime.default_hasher_string(&key, 0)
|
|
||||||
key_ptr := rawptr(&key)
|
key_ptr := rawptr(&key)
|
||||||
|
|
||||||
key_cstr: cstring
|
key_cstr: cstring
|
||||||
@@ -430,7 +427,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
key_ptr = &key_cstr
|
key_ptr = &key_cstr
|
||||||
}
|
}
|
||||||
|
|
||||||
set_ptr := runtime.__dynamic_map_set(raw_map, header, key_hash, key_ptr, map_backing_value.data)
|
set_ptr := runtime.__dynamic_map_set_without_hash(raw_map, t.map_info, key_ptr, map_backing_value.data)
|
||||||
if set_ptr == nil {
|
if set_ptr == nil {
|
||||||
delete(key, p.allocator)
|
delete(key, p.allocator)
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-104
@@ -162,7 +162,25 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
|
|||||||
p("Panic", message, loc)
|
p("Panic", message, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// formatted printing for cstrings
|
||||||
|
caprintf :: proc(format: string, args: ..any) -> cstring {
|
||||||
|
str: strings.Builder
|
||||||
|
strings.builder_init(&str)
|
||||||
|
sbprintf(&str, format, ..args)
|
||||||
|
strings.write_byte(&str, 0)
|
||||||
|
s := strings.to_string(str)
|
||||||
|
return cstring(raw_data(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// c string with temp allocator
|
||||||
|
ctprintf :: proc(format: string, args: ..any) -> cstring {
|
||||||
|
str: strings.Builder
|
||||||
|
strings.builder_init(&str, context.temp_allocator)
|
||||||
|
sbprintf(&str, format, ..args)
|
||||||
|
strings.write_byte(&str, 0)
|
||||||
|
s := strings.to_string(str)
|
||||||
|
return cstring(raw_data(s))
|
||||||
|
}
|
||||||
|
|
||||||
// sbprint formats using the default print settings and writes to buf
|
// sbprint formats using the default print settings and writes to buf
|
||||||
sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||||
@@ -240,7 +258,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
|
|||||||
was_prev_index := false
|
was_prev_index := false
|
||||||
|
|
||||||
loop: for i := 0; i < end; /**/ {
|
loop: for i := 0; i < end; /**/ {
|
||||||
fi = Info{writer = w, good_arg_index = true, reordered = fi.reordered}
|
fi = Info{writer = w, good_arg_index = true, reordered = fi.reordered, n = fi.n}
|
||||||
|
|
||||||
prev_i := i
|
prev_i := i
|
||||||
for i < end && !(fmt[i] == '%' || fmt[i] == '{' || fmt[i] == '}') {
|
for i < end && !(fmt[i] == '%' || fmt[i] == '{' || fmt[i] == '}') {
|
||||||
@@ -529,7 +547,7 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok:
|
|||||||
is_digit :: #force_inline proc(r: byte) -> bool { return '0' <= r && r <= '9' }
|
is_digit :: #force_inline proc(r: byte) -> bool { return '0' <= r && r <= '9' }
|
||||||
|
|
||||||
new_offset = offset
|
new_offset = offset
|
||||||
for new_offset <= len(s) {
|
for new_offset < len(s) {
|
||||||
c := s[new_offset]
|
c := s[new_offset]
|
||||||
if !is_digit(c) {
|
if !is_digit(c) {
|
||||||
break
|
break
|
||||||
@@ -660,7 +678,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
|
|||||||
}
|
}
|
||||||
} else if fi.zero && fi.width_set {
|
} else if fi.zero && fi.width_set {
|
||||||
prec = fi.width
|
prec = fi.width
|
||||||
if neg || fi.plus || fi.space {
|
if neg || fi.plus {
|
||||||
// There needs to be space for the "sign"
|
// There needs to be space for the "sign"
|
||||||
prec -= 1
|
prec -= 1
|
||||||
}
|
}
|
||||||
@@ -679,7 +697,6 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
|
|||||||
flags: strconv.Int_Flags
|
flags: strconv.Int_Flags
|
||||||
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
||||||
if fi.plus { flags |= {.Plus} }
|
if fi.plus { flags |= {.Plus} }
|
||||||
if fi.space { flags |= {.Space} }
|
|
||||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||||
|
|
||||||
if fi.hash && fi.zero && fi.indent == 0 {
|
if fi.hash && fi.zero && fi.indent == 0 {
|
||||||
@@ -726,7 +743,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
|
|||||||
}
|
}
|
||||||
} else if fi.zero && fi.width_set {
|
} else if fi.zero && fi.width_set {
|
||||||
prec = fi.width
|
prec = fi.width
|
||||||
if neg || fi.plus || fi.space {
|
if neg || fi.plus {
|
||||||
// There needs to be space for the "sign"
|
// There needs to be space for the "sign"
|
||||||
prec -= 1
|
prec -= 1
|
||||||
}
|
}
|
||||||
@@ -745,7 +762,6 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
|
|||||||
flags: strconv.Int_Flags
|
flags: strconv.Int_Flags
|
||||||
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
||||||
if fi.plus { flags |= {.Plus} }
|
if fi.plus { flags |= {.Plus} }
|
||||||
if fi.space { flags |= {.Space} }
|
|
||||||
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||||
|
|
||||||
if fi.hash && fi.zero && fi.indent == 0 {
|
if fi.hash && fi.zero && fi.indent == 0 {
|
||||||
@@ -849,79 +865,30 @@ _pad :: proc(fi: ^Info, s: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte) {
|
||||||
|
prec := fi.prec if fi.prec_set else 3
|
||||||
|
buf: [386]byte
|
||||||
|
|
||||||
|
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
|
||||||
|
str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size)
|
||||||
|
|
||||||
|
if !fi.plus {
|
||||||
|
// Strip sign from "+<value>" but not "+Inf".
|
||||||
|
if str[0] == '+' && str[1] != 'I' {
|
||||||
|
str = str[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_pad(fi, str)
|
||||||
|
}
|
||||||
|
|
||||||
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 'f', 'F', 'g', 'G', 'v':
|
case 'f', 'F', 'g', 'G', 'v':
|
||||||
prec: int = 3
|
_fmt_float_as(fi, v, bit_size, verb, 'f')
|
||||||
if fi.prec_set {
|
|
||||||
prec = fi.prec
|
|
||||||
}
|
|
||||||
buf: [386]byte
|
|
||||||
|
|
||||||
str := strconv.append_float(buf[1:], v, 'f', prec, bit_size)
|
|
||||||
b := buf[:len(str)+1]
|
|
||||||
if b[1] == '+' || b[1] == '-' {
|
|
||||||
b = b[1:]
|
|
||||||
} else {
|
|
||||||
b[0] = '+'
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.space && !fi.plus && b[0] == '+' {
|
|
||||||
b[0] = ' '
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
|
|
||||||
io.write_string(fi.writer, string(b), &fi.n)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.plus || b[0] != '+' {
|
|
||||||
if fi.zero && fi.width_set && fi.width > len(b) {
|
|
||||||
io.write_byte(fi.writer, b[0], &fi.n)
|
|
||||||
fmt_write_padding(fi, fi.width - len(b))
|
|
||||||
io.write_string(fi.writer, string(b[1:]), &fi.n)
|
|
||||||
} else {
|
|
||||||
_pad(fi, string(b))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_pad(fi, string(b[1:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'e', 'E':
|
case 'e', 'E':
|
||||||
prec: int = 3
|
// BUG(): "%.3e" returns "3.000e+00"
|
||||||
if fi.prec_set {
|
_fmt_float_as(fi, v, bit_size, verb, 'e')
|
||||||
prec = fi.prec
|
|
||||||
}
|
|
||||||
buf: [386]byte
|
|
||||||
|
|
||||||
str := strconv.append_float(buf[1:], v, 'e', prec, bit_size)
|
|
||||||
b := buf[:len(str)+1]
|
|
||||||
if b[1] == '+' || b[1] == '-' {
|
|
||||||
b = b[1:]
|
|
||||||
} else {
|
|
||||||
b[0] = '+'
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.space && !fi.plus && b[0] == '+' {
|
|
||||||
b[0] = ' '
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
|
|
||||||
io.write_string(fi.writer, string(b), &fi.n)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.plus || str[0] != '+' {
|
|
||||||
if fi.zero && fi.width_set && fi.width > len(b) {
|
|
||||||
io.write_byte(fi.writer, b[0], &fi.n)
|
|
||||||
fmt_write_padding(fi, fi.width - len(b))
|
|
||||||
io.write_string(fi.writer, string(b[1:]), &fi.n)
|
|
||||||
} else {
|
|
||||||
_pad(fi, string(b))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_pad(fi, string(b[1:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'h', 'H':
|
case 'h', 'H':
|
||||||
prev_fi := fi^
|
prev_fi := fi^
|
||||||
@@ -975,7 +942,7 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
io.write_string(fi.writer, s[:fi.width], &fi.n)
|
io.write_string(fi.writer, s, &fi.n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2051,41 +2018,27 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
|
|
||||||
m := (^mem.Raw_Map)(v.data)
|
m := (^mem.Raw_Map)(v.data)
|
||||||
if m != nil {
|
if m != nil {
|
||||||
if info.generated_struct == nil {
|
if info.map_info == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entries := &m.entries
|
map_cap := uintptr(runtime.map_cap(m^))
|
||||||
gs := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct)
|
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
|
||||||
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
|
j := 0
|
||||||
entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
|
for bucket_index in 0..<map_cap {
|
||||||
entry_size := ed.elem_size
|
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
||||||
/*
|
continue
|
||||||
NOTE: The layout of a `map` is as follows:
|
|
||||||
|
|
||||||
map[Key]Value
|
|
||||||
|
|
||||||
## Internal Layout
|
|
||||||
struct {
|
|
||||||
hashes: []int,
|
|
||||||
entries: [dynamic]struct{
|
|
||||||
hash: uintptr,
|
|
||||||
next: int,
|
|
||||||
key: Key,
|
|
||||||
value: Value,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
for i in 0..<entries.len {
|
|
||||||
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
|
|
||||||
|
|
||||||
data := uintptr(entries.data) + uintptr(i*entry_size)
|
if j > 0 {
|
||||||
|
io.write_string(fi.writer, ", ", &fi.n)
|
||||||
|
}
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index)
|
||||||
|
value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index)
|
||||||
|
|
||||||
key := data + entry_type.offsets[2] // key: Key
|
|
||||||
fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v')
|
fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v')
|
||||||
|
|
||||||
io.write_string(fi.writer, "=", &fi.n)
|
io.write_string(fi.writer, "=", &fi.n)
|
||||||
|
|
||||||
value := data + entry_type.offsets[3] // value: Value
|
|
||||||
fmt_arg(fi, any{rawptr(value), info.value.id}, 'v')
|
fmt_arg(fi, any{rawptr(value), info.value.id}, 'v')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
|
|||||||
w := io.to_writer(os.stream_from_handle(fd))
|
w := io.to_writer(os.stream_from_handle(fd))
|
||||||
return wprintln(w=w, args=args, sep=sep)
|
return wprintln(w=w, args=args, sep=sep)
|
||||||
}
|
}
|
||||||
// fprintf formats according to the specififed format string and writes to fd
|
// fprintf formats according to the specified format string and writes to fd
|
||||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||||
w := io.to_writer(os.stream_from_handle(fd))
|
w := io.to_writer(os.stream_from_handle(fd))
|
||||||
return wprintf(w, fmt, ..args)
|
return wprintf(w, fmt, ..args)
|
||||||
@@ -34,12 +34,12 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
|
|||||||
print :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) }
|
print :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) }
|
||||||
// println formats using the default print settings and writes to os.stdout
|
// println formats using the default print settings and writes to os.stdout
|
||||||
println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) }
|
println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) }
|
||||||
// printf formats according to the specififed format string and writes to os.stdout
|
// printf formats according to the specified format string and writes to os.stdout
|
||||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
|
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
|
||||||
|
|
||||||
// eprint formats using the default print settings and writes to os.stderr
|
// eprint formats using the default print settings and writes to os.stderr
|
||||||
eprint :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) }
|
eprint :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) }
|
||||||
// eprintln formats using the default print settings and writes to os.stderr
|
// eprintln formats using the default print settings and writes to os.stderr
|
||||||
eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) }
|
eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) }
|
||||||
// eprintf formats according to the specififed format string and writes to os.stderr
|
// eprintf formats according to the specified format string and writes to os.stderr
|
||||||
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }
|
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }
|
||||||
|
|||||||
+7
-3
@@ -72,8 +72,9 @@ djbx33a :: proc(data: []byte, seed := u32(5381)) -> (result: [16]byte) #no_bound
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If you have a choice, prefer fnv32a
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
fnv32 :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
|
fnv32_no_a :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
|
||||||
h: u32 = seed
|
h: u32 = seed
|
||||||
for b in data {
|
for b in data {
|
||||||
h = (h * 0x01000193) ~ u32(b)
|
h = (h * 0x01000193) ~ u32(b)
|
||||||
@@ -81,15 +82,18 @@ fnv32 :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fnv32 :: fnv32_no_a // NOTE(bill): Not a fan of these aliases but seems necessary
|
||||||
|
fnv64 :: fnv64_no_a // NOTE(bill): Not a fan of these aliases but seems necessary
|
||||||
|
|
||||||
|
// If you have a choice, prefer fnv64a
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
fnv64 :: proc(data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 {
|
fnv64_no_a :: proc(data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 {
|
||||||
h: u64 = seed
|
h: u64 = seed
|
||||||
for b in data {
|
for b in data {
|
||||||
h = (h * 0x100000001b3) ~ u64(b)
|
h = (h * 0x100000001b3) ~ u64(b)
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
fnv32a :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
|
fnv32a :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 {
|
||||||
h: u32 = seed
|
h: u32 = seed
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ XXH_mul_64_to_128_fold_64 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(optimization_mode="speed")
|
@(optimization_mode="speed")
|
||||||
XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, auto_cast shift: uint) -> (res: xxh_u64) {
|
XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, #any_int shift: uint) -> (res: xxh_u64) {
|
||||||
return v ~ (v >> shift)
|
return v ~ (v >> shift)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
An example of how to use `load`.
|
An example of how to use `load`.
|
||||||
*/
|
*/
|
||||||
//+ignore
|
//+build ignore
|
||||||
package png
|
package png
|
||||||
|
|
||||||
import "core:image"
|
import "core:image"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is purely for documentation
|
// This is purely for documentation
|
||||||
//+ignore
|
//+build ignore
|
||||||
package intrinsics
|
package intrinsics
|
||||||
|
|
||||||
// Package-Related
|
// Package-Related
|
||||||
@@ -188,6 +188,9 @@ type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
|
|||||||
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) ---
|
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) ---
|
||||||
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
||||||
|
|
||||||
|
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_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
|
||||||
|
|
||||||
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
|
|||||||
args = {la.prefix, padding, size, alignment},
|
args = {la.prefix, padding, size, alignment},
|
||||||
location = location,
|
location = location,
|
||||||
)
|
)
|
||||||
|
case .Alloc_Non_Zeroed:
|
||||||
|
logf(
|
||||||
|
level=la.level,
|
||||||
|
fmt_str = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)",
|
||||||
|
args = {la.prefix, padding, size, alignment},
|
||||||
|
location = location,
|
||||||
|
)
|
||||||
case .Free:
|
case .Free:
|
||||||
if old_size != 0 {
|
if old_size != 0 {
|
||||||
logf(
|
logf(
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
TODO: Handle +/- Infinity and NaN.
|
TODO: Handle +/- Infinity and NaN.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//+ignore
|
|
||||||
package math_big
|
package math_big
|
||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//+ignore
|
//+build ignore
|
||||||
package math_big
|
package math_big
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// core:math/linalg implements linear algebra procedures useful for 3D spatial transformations
|
||||||
|
package linalg
|
||||||
@@ -531,7 +531,7 @@ not_equal :: proc{not_equal_single, not_equal_array}
|
|||||||
|
|
||||||
any :: proc(x: $A/[$N]bool) -> (out: bool) {
|
any :: proc(x: $A/[$N]bool) -> (out: bool) {
|
||||||
for e in x {
|
for e in x {
|
||||||
if x {
|
if e {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+337
-19
@@ -114,6 +114,92 @@ exp :: proc{
|
|||||||
exp_f64, exp_f64le, exp_f64be,
|
exp_f64, exp_f64le, exp_f64be,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pow10_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(pow10_f16(f16(x))) }
|
||||||
|
pow10_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(pow10_f16(f16(x))) }
|
||||||
|
pow10_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(pow10_f32(f32(x))) }
|
||||||
|
pow10_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(pow10_f32(f32(x))) }
|
||||||
|
pow10_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(pow10_f64(f64(x))) }
|
||||||
|
pow10_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(pow10_f64(f64(x))) }
|
||||||
|
pow10 :: proc{
|
||||||
|
pow10_f16, pow10_f16le, pow10_f16be,
|
||||||
|
pow10_f32, pow10_f32le, pow10_f32be,
|
||||||
|
pow10_f64, pow10_f64le, pow10_f64be,
|
||||||
|
}
|
||||||
|
|
||||||
|
pow10_f16 :: proc "contextless" (n: f16) -> f16 {
|
||||||
|
@static pow10_pos_tab := [?]f16{
|
||||||
|
1e00, 1e01, 1e02, 1e03, 1e04,
|
||||||
|
}
|
||||||
|
@static pow10_neg_tab := [?]f16{
|
||||||
|
1e-00, 1e-01, 1e-02, 1e-03, 1e-04, 1e-05, 1e-06, 1e-07,
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 <= n && n <= 4 {
|
||||||
|
return pow10_pos_tab[uint(n)]
|
||||||
|
}
|
||||||
|
if -7 <= n && n <= 0 {
|
||||||
|
return pow10_neg_tab[uint(-n)]
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
return inf_f16(1)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pow10_f32 :: proc "contextless" (n: f32) -> f32 {
|
||||||
|
@static pow10_pos_tab := [?]f32{
|
||||||
|
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||||
|
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
|
||||||
|
1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38,
|
||||||
|
}
|
||||||
|
@static pow10_neg_tab := [?]f32{
|
||||||
|
1e-00, 1e-01, 1e-02, 1e-03, 1e-04, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09,
|
||||||
|
1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19,
|
||||||
|
1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29,
|
||||||
|
1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 1e-39,
|
||||||
|
1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45,
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 <= n && n <= 38 {
|
||||||
|
return pow10_pos_tab[uint(n)]
|
||||||
|
}
|
||||||
|
if -45 <= n && n <= 0 {
|
||||||
|
return pow10_neg_tab[uint(-n)]
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
return inf_f32(1)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pow10_f64 :: proc "contextless" (n: f64) -> f64 {
|
||||||
|
@static pow10_tab := [?]f64{
|
||||||
|
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||||
|
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
|
||||||
|
1e30, 1e31,
|
||||||
|
}
|
||||||
|
@static pow10_pos_tab32 := [?]f64{
|
||||||
|
1e00, 1e32, 1e64, 1e96, 1e128, 1e160, 1e192, 1e224, 1e256, 1e288,
|
||||||
|
}
|
||||||
|
@static pow10_neg_tab32 := [?]f64{
|
||||||
|
1e-00, 1e-32, 1e-64, 1e-96, 1e-128, 1e-160, 1e-192, 1e-224, 1e-256, 1e-288, 1e-320,
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 <= n && n <= 308 {
|
||||||
|
return pow10_pos_tab32[uint(n)/32] * pow10_tab[uint(n)%32]
|
||||||
|
}
|
||||||
|
if -323 <= n && n <= 0 {
|
||||||
|
return pow10_neg_tab32[uint(-n)/32] / pow10_tab[uint(-n)%32]
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
return inf_f64(1)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ldexp_f64 :: proc "contextless" (val: f64, exp: int) -> f64 {
|
ldexp_f64 :: proc "contextless" (val: f64, exp: int) -> f64 {
|
||||||
@@ -1088,7 +1174,7 @@ is_nan :: proc{
|
|||||||
// If sign < 0, is_inf reports whether f is negative infinity.
|
// If sign < 0, is_inf reports whether f is negative infinity.
|
||||||
// If sign == 0, is_inf reports whether f is either infinity.
|
// If sign == 0, is_inf reports whether f is either infinity.
|
||||||
is_inf_f16 :: proc "contextless" (x: f16, sign: int = 0) -> bool {
|
is_inf_f16 :: proc "contextless" (x: f16, sign: int = 0) -> bool {
|
||||||
class := classify(abs(x))
|
class := classify(x)
|
||||||
switch {
|
switch {
|
||||||
case sign > 0:
|
case sign > 0:
|
||||||
return class == .Inf
|
return class == .Inf
|
||||||
@@ -1105,7 +1191,7 @@ is_inf_f16be :: proc "contextless" (x: f16be, sign: int = 0) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_inf_f32 :: proc "contextless" (x: f32, sign: int = 0) -> bool {
|
is_inf_f32 :: proc "contextless" (x: f32, sign: int = 0) -> bool {
|
||||||
class := classify(abs(x))
|
class := classify(x)
|
||||||
switch {
|
switch {
|
||||||
case sign > 0:
|
case sign > 0:
|
||||||
return class == .Inf
|
return class == .Inf
|
||||||
@@ -1122,7 +1208,7 @@ is_inf_f32be :: proc "contextless" (x: f32be, sign: int = 0) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_inf_f64 :: proc "contextless" (x: f64, sign: int = 0) -> bool {
|
is_inf_f64 :: proc "contextless" (x: f64, sign: int = 0) -> bool {
|
||||||
class := classify(abs(x))
|
class := classify(x)
|
||||||
switch {
|
switch {
|
||||||
case sign > 0:
|
case sign > 0:
|
||||||
return class == .Inf
|
return class == .Inf
|
||||||
@@ -1344,20 +1430,20 @@ atan2_f64 :: proc "contextless" (y, x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
return copy_sign(PI, y)
|
return copy_sign(PI, y)
|
||||||
case x == 0:
|
case x == 0:
|
||||||
return copy_sign(PI*0.5, y)
|
return copy_sign(PI/2, y)
|
||||||
case is_inf(x, 0):
|
case is_inf(x, 0):
|
||||||
if is_inf(x, 1) {
|
if is_inf(x, 1) {
|
||||||
if is_inf(y, 0) {
|
if is_inf(y, 0) {
|
||||||
return copy_sign(PI*0.25, y)
|
return copy_sign(PI/4, y)
|
||||||
}
|
}
|
||||||
return copy_sign(0, y)
|
return copy_sign(0, y)
|
||||||
}
|
}
|
||||||
if is_inf(y, 0) {
|
if is_inf(y, 0) {
|
||||||
return copy_sign(PI*0.75, y)
|
return copy_sign(3*PI/4, y)
|
||||||
}
|
}
|
||||||
return copy_sign(PI, y)
|
return copy_sign(PI, y)
|
||||||
case is_inf(y, 0):
|
case is_inf(y, 0):
|
||||||
return copy_sign(PI*0.5, y)
|
return copy_sign(PI/2, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
q := atan(y / x)
|
q := atan(y / x)
|
||||||
@@ -1379,34 +1465,266 @@ atan2_f64be :: proc "contextless" (y, x: f64be) -> f64be {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atan2 :: proc{
|
atan2 :: proc{
|
||||||
atan2_f16, atan2_f16le, atan2_f16be,
|
atan2_f64, atan2_f32, atan2_f16,
|
||||||
atan2_f32, atan2_f32le, atan2_f32be,
|
atan2_f64le, atan2_f64be,
|
||||||
atan2_f64, atan2_f64le, atan2_f64be,
|
atan2_f32le, atan2_f32be,
|
||||||
|
atan2_f16le, atan2_f16be,
|
||||||
}
|
}
|
||||||
|
|
||||||
atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
return atan2(x, 1)
|
return atan2(x, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
asin :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
|
||||||
return atan2(x, sqrt(1 - x*x))
|
|
||||||
|
asin_f64 :: proc "contextless" (x: f64) -> f64 {
|
||||||
|
/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */
|
||||||
|
/*
|
||||||
|
* ====================================================
|
||||||
|
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||||
|
* Permission to use, copy, modify, and distribute this
|
||||||
|
* software is freely granted, provided that this notice
|
||||||
|
* is preserved.
|
||||||
|
* ====================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
pio2_hi :: 0h3FF921FB54442D18
|
||||||
|
pio2_lo :: 0h3C91A62633145C07
|
||||||
|
pS0 :: 0h3FC5555555555555
|
||||||
|
pS1 :: 0hBFD4D61203EB6F7D
|
||||||
|
pS2 :: 0h3FC9C1550E884455
|
||||||
|
pS3 :: 0hBFA48228B5688F3B
|
||||||
|
pS4 :: 0h3F49EFE07501B288
|
||||||
|
pS5 :: 0h3F023DE10DFDF709
|
||||||
|
qS1 :: 0hC0033A271C8A2D4B
|
||||||
|
qS2 :: 0h40002AE59C598AC8
|
||||||
|
qS3 :: 0hBFE6066C1B8D0159
|
||||||
|
qS4 :: 0h3FB3B8C5B12E9282
|
||||||
|
|
||||||
|
R :: #force_inline proc "contextless" (z: f64) -> f64 {
|
||||||
|
p, q: f64
|
||||||
|
p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))))
|
||||||
|
q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)))
|
||||||
|
return p/q
|
||||||
|
}
|
||||||
|
|
||||||
|
x := x
|
||||||
|
z, r, s: f64
|
||||||
|
dwords := transmute([2]u32)x
|
||||||
|
hx := dwords[1]
|
||||||
|
ix := hx & 0x7fffffff
|
||||||
|
/* |x| >= 1 or nan */
|
||||||
|
if ix >= 0x3ff00000 {
|
||||||
|
lx := dwords[0]
|
||||||
|
if (ix-0x3ff00000 | lx) == 0 {
|
||||||
|
/* asin(1) = +-pi/2 with inexact */
|
||||||
|
return x*pio2_hi + 1e-120
|
||||||
|
}
|
||||||
|
return 0/(x-x)
|
||||||
|
}
|
||||||
|
/* |x| < 0.5 */
|
||||||
|
if ix < 0x3fe00000 {
|
||||||
|
/* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
|
||||||
|
if ix < 0x3e500000 && ix >= 0x00100000 {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return x + x*R(x*x)
|
||||||
|
}
|
||||||
|
/* 1 > |x| >= 0.5 */
|
||||||
|
z = (1 - abs(x))*0.5
|
||||||
|
s = sqrt(z)
|
||||||
|
r = R(z)
|
||||||
|
if ix >= 0x3fef3333 { /* if |x| > 0.975 */
|
||||||
|
x = pio2_hi-(2*(s+s*r)-pio2_lo)
|
||||||
|
} else {
|
||||||
|
f, c: f64
|
||||||
|
/* f+c = sqrt(z) */
|
||||||
|
f = s
|
||||||
|
(^u64)(&f)^ &= 0xffffffff_00000000
|
||||||
|
c = (z-f*f)/(s+f)
|
||||||
|
x = 0.5*pio2_hi - (2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f))
|
||||||
|
}
|
||||||
|
return -x if hx >> 31 != 0 else x
|
||||||
|
}
|
||||||
|
asin_f64le :: proc "contextless" (x: f64le) -> f64le {
|
||||||
|
return f64le(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f64be :: proc "contextless" (x: f64be) -> f64be {
|
||||||
|
return f64be(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f32 :: proc "contextless" (x: f32) -> f32 {
|
||||||
|
return f32(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f32le :: proc "contextless" (x: f32le) -> f32le {
|
||||||
|
return f32le(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f32be :: proc "contextless" (x: f32be) -> f32be {
|
||||||
|
return f32be(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f16 :: proc "contextless" (x: f16) -> f16 {
|
||||||
|
return f16(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f16le :: proc "contextless" (x: f16le) -> f16le {
|
||||||
|
return f16le(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin_f16be :: proc "contextless" (x: f16be) -> f16be {
|
||||||
|
return f16be(asin_f64(f64(x)))
|
||||||
|
}
|
||||||
|
asin :: proc{
|
||||||
|
asin_f64, asin_f32, asin_f16,
|
||||||
|
asin_f64le, asin_f64be,
|
||||||
|
asin_f32le, asin_f32be,
|
||||||
|
asin_f16le, asin_f16be,
|
||||||
}
|
}
|
||||||
|
|
||||||
acos :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
|
||||||
return 2 * atan2(sqrt(1 - x), sqrt(1 + x))
|
acos_f64 :: proc "contextless" (x: f64) -> f64 {
|
||||||
|
/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */
|
||||||
|
/*
|
||||||
|
* ====================================================
|
||||||
|
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||||
|
* Permission to use, copy, modify, and distribute this
|
||||||
|
* software is freely granted, provided that this notice
|
||||||
|
* is preserved.
|
||||||
|
* ====================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
pio2_hi :: 0h3FF921FB54442D18
|
||||||
|
pio2_lo :: 0h3C91A62633145C07
|
||||||
|
pS0 :: 0h3FC5555555555555
|
||||||
|
pS1 :: 0hBFD4D61203EB6F7D
|
||||||
|
pS2 :: 0h3FC9C1550E884455
|
||||||
|
pS3 :: 0hBFA48228B5688F3B
|
||||||
|
pS4 :: 0h3F49EFE07501B288
|
||||||
|
pS5 :: 0h3F023DE10DFDF709
|
||||||
|
qS1 :: 0hC0033A271C8A2D4B
|
||||||
|
qS2 :: 0h40002AE59C598AC8
|
||||||
|
qS3 :: 0hBFE6066C1B8D0159
|
||||||
|
qS4 :: 0h3FB3B8C5B12E9282
|
||||||
|
|
||||||
|
R :: #force_inline proc "contextless" (z: f64) -> f64 {
|
||||||
|
p, q: f64
|
||||||
|
p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))))
|
||||||
|
q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)))
|
||||||
|
return p/q
|
||||||
|
}
|
||||||
|
|
||||||
|
z, w, s, c, df: f64
|
||||||
|
dwords := transmute([2]u32)x
|
||||||
|
hx := dwords[1]
|
||||||
|
ix := hx & 0x7fffffff
|
||||||
|
/* |x| >= 1 or nan */
|
||||||
|
if ix >= 0x3ff00000 {
|
||||||
|
lx := dwords[0]
|
||||||
|
|
||||||
|
if (ix-0x3ff00000 | lx) == 0 {
|
||||||
|
/* acos(1)=0, acos(-1)=pi */
|
||||||
|
if hx >> 31 != 0 {
|
||||||
|
return 2*pio2_hi + 1e-120
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 0/(x-x)
|
||||||
|
}
|
||||||
|
/* |x| < 0.5 */
|
||||||
|
if ix < 0x3fe00000 {
|
||||||
|
if ix <= 0x3c600000 { /* |x| < 2**-57 */
|
||||||
|
return pio2_hi + 1e-120
|
||||||
|
}
|
||||||
|
return pio2_hi - (x - (pio2_lo-x*R(x*x)))
|
||||||
|
}
|
||||||
|
/* x < -0.5 */
|
||||||
|
if hx >> 31 != 0 {
|
||||||
|
z = (1.0+x)*0.5
|
||||||
|
s = sqrt(z)
|
||||||
|
w = R(z)*s-pio2_lo
|
||||||
|
return 2*(pio2_hi - (s+w))
|
||||||
|
}
|
||||||
|
/* x > 0.5 */
|
||||||
|
z = (1.0-x)*0.5
|
||||||
|
s = sqrt(z)
|
||||||
|
df = s
|
||||||
|
(^u64)(&df)^ &= 0xffffffff_00000000
|
||||||
|
c = (z-df*df)/(s+df)
|
||||||
|
w = R(z)*s+c
|
||||||
|
return 2*(df+w)
|
||||||
|
}
|
||||||
|
acos_f64le :: proc "contextless" (x: f64le) -> f64le {
|
||||||
|
return f64le(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f64be :: proc "contextless" (x: f64be) -> f64be {
|
||||||
|
return f64be(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f32 :: proc "contextless" (x: f32) -> f32 {
|
||||||
|
return f32(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f32le :: proc "contextless" (x: f32le) -> f32le {
|
||||||
|
return f32le(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f32be :: proc "contextless" (x: f32be) -> f32be {
|
||||||
|
return f32be(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f16 :: proc "contextless" (x: f16) -> f16 {
|
||||||
|
return f16(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f16le :: proc "contextless" (x: f16le) -> f16le {
|
||||||
|
return f16le(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos_f16be :: proc "contextless" (x: f16be) -> f16be {
|
||||||
|
return f16be(acos_f64(f64(x)))
|
||||||
|
}
|
||||||
|
acos :: proc{
|
||||||
|
acos_f64, acos_f32, acos_f16,
|
||||||
|
acos_f64le, acos_f64be,
|
||||||
|
acos_f32le, acos_f32be,
|
||||||
|
acos_f16le, acos_f16be,
|
||||||
}
|
}
|
||||||
|
|
||||||
sinh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
sinh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
return (exp(x) - exp(-x))*0.5
|
return copy_sign(((exp(x) - exp(-x))*0.5), x)
|
||||||
}
|
}
|
||||||
|
|
||||||
cosh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
cosh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
return (exp(x) + exp(-x))*0.5
|
return ((exp(x) + exp(-x))*0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
tanh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
tanh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
t := exp(2*x)
|
P0 :: -9.64399179425052238628e-1
|
||||||
return (t - 1) / (t + 1)
|
P1 :: -9.92877231001918586564e1
|
||||||
|
P2 :: -1.61468768441708447952e3
|
||||||
|
Q0 :: +1.12811678491632931402e2
|
||||||
|
Q1 :: +2.23548839060100448583e3
|
||||||
|
Q2 :: +4.84406305325125486048e3
|
||||||
|
|
||||||
|
MAXLOG :: 8.8029691931113054295988e+01 // log(2**127)
|
||||||
|
|
||||||
|
|
||||||
|
x := f64(y)
|
||||||
|
z := abs(x)
|
||||||
|
switch {
|
||||||
|
case z > 0.5*MAXLOG:
|
||||||
|
if x < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
case z >= 0.625:
|
||||||
|
s := exp(2 * z)
|
||||||
|
z = 1 - 2/(s+1)
|
||||||
|
if x < 0 {
|
||||||
|
z = -z
|
||||||
|
}
|
||||||
|
case:
|
||||||
|
if x == 0 {
|
||||||
|
return T(x)
|
||||||
|
}
|
||||||
|
s := x * x
|
||||||
|
z = x + x*s*((P0*s+P1)*s+P2)/(((s+Q0)*s+Q1)*s+Q2)
|
||||||
|
}
|
||||||
|
return T(z)
|
||||||
}
|
}
|
||||||
|
|
||||||
asinh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) {
|
asinh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
|||||||
@@ -182,3 +182,12 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
|
|||||||
array[i], array[j] = array[j], array[i]
|
array[i], array[j] = array[j], array[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a random element from the given slice
|
||||||
|
choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
|
||||||
|
n := i64(len(array))
|
||||||
|
if n < 1 {
|
||||||
|
return E{}
|
||||||
|
}
|
||||||
|
return array[int63_max(n, r)]
|
||||||
|
}
|
||||||
+25
-17
@@ -69,10 +69,22 @@ alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator :=
|
|||||||
return runtime.mem_alloc(size, alignment, allocator, loc)
|
return runtime.mem_alloc(size, alignment, allocator, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||||
|
return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc)
|
||||||
|
}
|
||||||
|
|
||||||
free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
return runtime.mem_free(ptr, allocator, loc)
|
return runtime.mem_free(ptr, allocator, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_with_size :: proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
|
if ptr == nil || allocator.procedure == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
return runtime.mem_free_bytes(bytes, allocator, loc)
|
return runtime.mem_free_bytes(bytes, allocator, loc)
|
||||||
}
|
}
|
||||||
@@ -108,22 +120,20 @@ query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_locatio
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) {
|
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
free(raw_data(str), allocator, loc)
|
return free_with_size(raw_data(str), len(str), allocator, loc)
|
||||||
}
|
}
|
||||||
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) {
|
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
free((^byte)(str), allocator, loc)
|
return free((^byte)(str), allocator, loc)
|
||||||
}
|
}
|
||||||
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) {
|
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
|
||||||
free(raw_data(array), array.allocator, loc)
|
return free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
|
||||||
}
|
}
|
||||||
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) {
|
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
free(raw_data(array), allocator, loc)
|
return free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
|
||||||
}
|
}
|
||||||
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) {
|
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
|
||||||
raw := transmute(Raw_Map)m
|
return runtime.map_free_dynamic(transmute(Raw_Map)m, runtime.map_info(T), loc)
|
||||||
delete_slice(raw.hashes, raw.entries.allocator, loc)
|
|
||||||
free(raw.entries.data, raw.entries.allocator, loc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -154,8 +164,6 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
|
|||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_RESERVE_CAPACITY :: 16
|
|
||||||
|
|
||||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
|
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
|
||||||
runtime.make_slice_error_loc(loc, len)
|
runtime.make_slice_error_loc(loc, len)
|
||||||
data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return
|
data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return
|
||||||
@@ -169,7 +177,7 @@ make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allo
|
|||||||
return make_aligned(T, len, align_of(E), allocator, loc)
|
return make_aligned(T, len, align_of(E), allocator, loc)
|
||||||
}
|
}
|
||||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
|
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
|
||||||
return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc)
|
return make_dynamic_array_len_cap(T, 0, 16, allocator, loc)
|
||||||
}
|
}
|
||||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
|
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
|
||||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
return make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
||||||
@@ -184,12 +192,12 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
|
|||||||
array = transmute(T)s
|
array = transmute(T)s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
|
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
|
||||||
runtime.make_map_expr_error_loc(loc, cap)
|
runtime.make_map_expr_error_loc(loc, cap)
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
m: T
|
m: T
|
||||||
reserve_map(&m, cap)
|
reserve_map(&m, cap, loc)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
|
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
|
||||||
|
|||||||
+61
-35
@@ -59,7 +59,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
arena := cast(^Arena)allocator_data
|
arena := cast(^Arena)allocator_data
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
#no_bounds_check end := &arena.data[arena.offset]
|
#no_bounds_check end := &arena.data[arena.offset]
|
||||||
|
|
||||||
ptr := align_forward(end, uintptr(alignment))
|
ptr := align_forward(end, uintptr(alignment))
|
||||||
@@ -72,7 +72,9 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
arena.offset += total_size
|
arena.offset += total_size
|
||||||
arena.peak_used = max(arena.peak_used, arena.offset)
|
arena.peak_used = max(arena.peak_used, arena.offset)
|
||||||
zero(ptr, size)
|
if mode != .Alloc_Non_Zeroed {
|
||||||
|
zero(ptr, size)
|
||||||
|
}
|
||||||
return byte_slice(ptr, size), nil
|
return byte_slice(ptr, size), nil
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
@@ -87,7 +89,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free_All, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
@@ -151,7 +153,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
s := (^Scratch_Allocator)(allocator_data)
|
s := (^Scratch_Allocator)(allocator_data)
|
||||||
|
|
||||||
if s.data == nil {
|
if s.data == nil {
|
||||||
DEFAULT_BACKING_SIZE :: 1<<22
|
DEFAULT_BACKING_SIZE :: 4 * Megabyte
|
||||||
if !(context.allocator.procedure != scratch_allocator_proc &&
|
if !(context.allocator.procedure != scratch_allocator_proc &&
|
||||||
context.allocator.data != allocator_data) {
|
context.allocator.data != allocator_data) {
|
||||||
panic("cyclic initialization of the scratch allocator with itself")
|
panic("cyclic initialization of the scratch allocator with itself")
|
||||||
@@ -162,7 +164,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
size := size
|
size := size
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
size = align_forward_int(size, alignment)
|
size = align_forward_int(size, alignment)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@@ -170,7 +172,9 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
start := uintptr(raw_data(s.data))
|
start := uintptr(raw_data(s.data))
|
||||||
ptr := start + uintptr(s.curr_offset)
|
ptr := start + uintptr(s.curr_offset)
|
||||||
ptr = align_forward_uintptr(ptr, uintptr(alignment))
|
ptr = align_forward_uintptr(ptr, uintptr(alignment))
|
||||||
zero(rawptr(ptr), size)
|
if mode != .Alloc_Non_Zeroed {
|
||||||
|
zero(rawptr(ptr), size)
|
||||||
|
}
|
||||||
|
|
||||||
s.prev_allocation = rawptr(ptr)
|
s.prev_allocation = rawptr(ptr)
|
||||||
offset := int(ptr - start)
|
offset := int(ptr - start)
|
||||||
@@ -180,7 +184,9 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case size <= len(s.data):
|
case size <= len(s.data):
|
||||||
start := uintptr(raw_data(s.data))
|
start := uintptr(raw_data(s.data))
|
||||||
ptr := align_forward_uintptr(start, uintptr(alignment))
|
ptr := align_forward_uintptr(start, uintptr(alignment))
|
||||||
zero(rawptr(ptr), size)
|
if mode != .Alloc_Non_Zeroed {
|
||||||
|
zero(rawptr(ptr), size)
|
||||||
|
}
|
||||||
|
|
||||||
s.prev_allocation = rawptr(ptr)
|
s.prev_allocation = rawptr(ptr)
|
||||||
offset := int(ptr - start)
|
offset := int(ptr - start)
|
||||||
@@ -211,6 +217,9 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
return ptr, err
|
return ptr, err
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
|
if old_memory == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
start := uintptr(raw_data(s.data))
|
start := uintptr(raw_data(s.data))
|
||||||
end := start + uintptr(len(s.data))
|
end := start + uintptr(len(s.data))
|
||||||
old_ptr := uintptr(old_memory)
|
old_ptr := uintptr(old_memory)
|
||||||
@@ -266,7 +275,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
@@ -333,7 +342,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
return nil, .Invalid_Argument
|
return nil, .Invalid_Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_alloc :: proc(s: ^Stack, size, alignment: int) -> ([]byte, Allocator_Error) {
|
raw_alloc :: proc(s: ^Stack, size, alignment: int, zero_memory: bool) -> ([]byte, Allocator_Error) {
|
||||||
curr_addr := uintptr(raw_data(s.data)) + uintptr(s.curr_offset)
|
curr_addr := uintptr(raw_data(s.data)) + uintptr(s.curr_offset)
|
||||||
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Stack_Allocation_Header))
|
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Stack_Allocation_Header))
|
||||||
if s.curr_offset + padding + size > len(s.data) {
|
if s.curr_offset + padding + size > len(s.data) {
|
||||||
@@ -351,13 +360,15 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
s.peak_used = max(s.peak_used, s.curr_offset)
|
s.peak_used = max(s.peak_used, s.curr_offset)
|
||||||
|
|
||||||
zero(rawptr(next_addr), size)
|
if zero_memory {
|
||||||
|
zero(rawptr(next_addr), size)
|
||||||
|
}
|
||||||
return byte_slice(rawptr(next_addr), size), nil
|
return byte_slice(rawptr(next_addr), size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return raw_alloc(s, size, alignment)
|
return raw_alloc(s, size, alignment, mode == .Alloc)
|
||||||
case .Free:
|
case .Free:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -392,7 +403,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
case .Resize:
|
case .Resize:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return raw_alloc(s, size, alignment)
|
return raw_alloc(s, size, alignment, true)
|
||||||
}
|
}
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -418,7 +429,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
|
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
|
||||||
|
|
||||||
if old_offset != header.prev_offset {
|
if old_offset != header.prev_offset {
|
||||||
data, err := raw_alloc(s, size, alignment)
|
data, err := raw_alloc(s, size, alignment, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
runtime.copy(data, byte_slice(old_memory, old_size))
|
runtime.copy(data, byte_slice(old_memory, old_size))
|
||||||
}
|
}
|
||||||
@@ -439,7 +450,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
case .Query_Info:
|
case .Query_Info:
|
||||||
@@ -497,7 +508,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
align := clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2)
|
align := clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2)
|
||||||
|
|
||||||
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> ([]byte, Allocator_Error) {
|
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int, zero_memory: bool) -> ([]byte, Allocator_Error) {
|
||||||
curr_addr := uintptr(raw_data(s.data)) + uintptr(s.offset)
|
curr_addr := uintptr(raw_data(s.data)) + uintptr(s.offset)
|
||||||
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header))
|
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header))
|
||||||
if s.offset + padding + size > len(s.data) {
|
if s.offset + padding + size > len(s.data) {
|
||||||
@@ -513,13 +524,15 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
s.peak_used = max(s.peak_used, s.offset)
|
s.peak_used = max(s.peak_used, s.offset)
|
||||||
|
|
||||||
zero(rawptr(next_addr), size)
|
if zero_memory {
|
||||||
|
zero(rawptr(next_addr), size)
|
||||||
|
}
|
||||||
return byte_slice(rawptr(next_addr), size), nil
|
return byte_slice(rawptr(next_addr), size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return raw_alloc(s, size, align)
|
return raw_alloc(s, size, align, mode == .Alloc)
|
||||||
case .Free:
|
case .Free:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -548,7 +561,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
case .Resize:
|
case .Resize:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return raw_alloc(s, size, align)
|
return raw_alloc(s, size, align, true)
|
||||||
}
|
}
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -571,7 +584,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
return byte_slice(old_memory, size), nil
|
return byte_slice(old_memory, size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := raw_alloc(s, size, align)
|
data, err := raw_alloc(s, size, align, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
runtime.copy(data, byte_slice(old_memory, old_size))
|
runtime.copy(data, byte_slice(old_memory, old_size))
|
||||||
}
|
}
|
||||||
@@ -580,7 +593,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
@@ -623,7 +636,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode
|
|||||||
pool := (^Dynamic_Pool)(allocator_data)
|
pool := (^Dynamic_Pool)(allocator_data)
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return dynamic_pool_alloc_bytes(pool, size)
|
return dynamic_pool_alloc_bytes(pool, size)
|
||||||
case .Free:
|
case .Free:
|
||||||
return nil, .Mode_Not_Implemented
|
return nil, .Mode_Not_Implemented
|
||||||
@@ -643,7 +656,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free_All, .Resize, .Query_Features, .Query_Info}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features, .Query_Info}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
@@ -794,6 +807,10 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
if size > 0 {
|
if size > 0 {
|
||||||
panic("mem: panic allocator, .Alloc called")
|
panic("mem: panic allocator, .Alloc called")
|
||||||
}
|
}
|
||||||
|
case .Alloc_Non_Zeroed:
|
||||||
|
if size > 0 {
|
||||||
|
panic("mem: panic allocator, .Alloc_Non_Zeroed called")
|
||||||
|
}
|
||||||
case .Resize:
|
case .Resize:
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
panic("mem: panic allocator, .Resize called")
|
panic("mem: panic allocator, .Resize called")
|
||||||
@@ -831,6 +848,7 @@ Tracking_Allocator_Entry :: struct {
|
|||||||
memory: rawptr,
|
memory: rawptr,
|
||||||
size: int,
|
size: int,
|
||||||
alignment: int,
|
alignment: int,
|
||||||
|
mode: Allocator_Mode,
|
||||||
err: Allocator_Error,
|
err: Allocator_Error,
|
||||||
location: runtime.Source_Code_Location,
|
location: runtime.Source_Code_Location,
|
||||||
}
|
}
|
||||||
@@ -849,6 +867,10 @@ tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Alloc
|
|||||||
t.backing = backing_allocator
|
t.backing = backing_allocator
|
||||||
t.allocation_map.allocator = internals_allocator
|
t.allocation_map.allocator = internals_allocator
|
||||||
t.bad_free_array.allocator = internals_allocator
|
t.bad_free_array.allocator = internals_allocator
|
||||||
|
|
||||||
|
if .Free_All in query_features(t.backing) {
|
||||||
|
t.clear_on_free_all = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
|
tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
|
||||||
@@ -856,6 +878,13 @@ tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
|
|||||||
delete(t.bad_free_array)
|
delete(t.bad_free_array)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
|
||||||
|
clear(&t.allocation_map)
|
||||||
|
clear(&t.bad_free_array)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
||||||
return Allocator{
|
return Allocator{
|
||||||
data = data,
|
data = data,
|
||||||
@@ -865,7 +894,7 @@ tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
|||||||
|
|
||||||
tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
|
||||||
data := (^Tracking_Allocator)(allocator_data)
|
data := (^Tracking_Allocator)(allocator_data)
|
||||||
if mode == .Query_Info {
|
if mode == .Query_Info {
|
||||||
info := (^Allocator_Query_Info)(old_memory)
|
info := (^Allocator_Query_Info)(old_memory)
|
||||||
@@ -877,21 +906,16 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
info.pointer = nil
|
info.pointer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result: []byte
|
|
||||||
err: Allocator_Error
|
|
||||||
if mode == .Free && old_memory != nil && old_memory not_in data.allocation_map {
|
if mode == .Free && old_memory != nil && old_memory not_in data.allocation_map {
|
||||||
append(&data.bad_free_array, Tracking_Allocator_Bad_Free_Entry{
|
append(&data.bad_free_array, Tracking_Allocator_Bad_Free_Entry{
|
||||||
memory = old_memory,
|
memory = old_memory,
|
||||||
location = loc,
|
location = loc,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result, err = data.backing.procedure(data.backing.data, mode, size, alignment, old_memory, old_size, loc)
|
result = data.backing.procedure(data.backing.data, mode, size, alignment, old_memory, old_size, loc) or_return
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result_ptr := raw_data(result)
|
result_ptr := raw_data(result)
|
||||||
|
|
||||||
@@ -900,10 +924,11 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
data.allocation_map[result_ptr] = Tracking_Allocator_Entry{
|
data.allocation_map[result_ptr] = Tracking_Allocator_Entry{
|
||||||
memory = result_ptr,
|
memory = result_ptr,
|
||||||
size = size,
|
size = size,
|
||||||
|
mode = mode,
|
||||||
alignment = alignment,
|
alignment = alignment,
|
||||||
err = err,
|
err = err,
|
||||||
location = loc,
|
location = loc,
|
||||||
@@ -921,6 +946,7 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
data.allocation_map[result_ptr] = Tracking_Allocator_Entry{
|
data.allocation_map[result_ptr] = Tracking_Allocator_Entry{
|
||||||
memory = result_ptr,
|
memory = result_ptr,
|
||||||
size = size,
|
size = size,
|
||||||
|
mode = mode,
|
||||||
alignment = alignment,
|
alignment = alignment,
|
||||||
err = err,
|
err = err,
|
||||||
location = loc,
|
location = loc,
|
||||||
@@ -929,7 +955,7 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features, .Query_Info}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features, .Query_Info}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
@@ -937,6 +963,6 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -3,11 +3,11 @@ package mem
|
|||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
Byte :: 1
|
Byte :: runtime.Byte
|
||||||
Kilobyte :: 1024 * Byte
|
Kilobyte :: runtime.Kilobyte
|
||||||
Megabyte :: 1024 * Kilobyte
|
Megabyte :: runtime.Megabyte
|
||||||
Gigabyte :: 1024 * Megabyte
|
Gigabyte :: runtime.Gigabyte
|
||||||
Terabyte :: 1024 * Gigabyte
|
Terabyte :: runtime.Terabyte
|
||||||
|
|
||||||
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
||||||
return runtime.memset(data, i32(value), len)
|
return runtime.memset(data, i32(value), len)
|
||||||
|
|||||||
+2
-19
@@ -1,5 +1,6 @@
|
|||||||
package mem
|
package mem
|
||||||
|
|
||||||
|
import "core:builtin"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
|
||||||
Raw_Any :: runtime.Raw_Any
|
Raw_Any :: runtime.Raw_Any
|
||||||
@@ -21,22 +22,4 @@ make_any :: proc "contextless" (data: rawptr, id: typeid) -> any {
|
|||||||
return transmute(any)Raw_Any{data, id}
|
return transmute(any)Raw_Any{data, id}
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_array_data :: runtime.raw_array_data
|
raw_data :: builtin.raw_data
|
||||||
raw_simd_data :: runtime.raw_simd_data
|
|
||||||
raw_string_data :: runtime.raw_string_data
|
|
||||||
raw_slice_data :: runtime.raw_slice_data
|
|
||||||
raw_dynamic_array_data :: runtime.raw_dynamic_array_data
|
|
||||||
raw_data :: runtime.raw_data
|
|
||||||
|
|
||||||
|
|
||||||
Poly_Raw_Map_Entry :: struct($Key, $Value: typeid) {
|
|
||||||
hash: uintptr,
|
|
||||||
next: int,
|
|
||||||
key: Key,
|
|
||||||
value: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
Poly_Raw_Map :: struct($Key, $Value: typeid) {
|
|
||||||
hashes: []int,
|
|
||||||
entries: [dynamic]Poly_Raw_Map_Entry(Key, Value),
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,354 @@
|
|||||||
|
package mem_virtual
|
||||||
|
|
||||||
|
import "core:mem"
|
||||||
|
import "core:sync"
|
||||||
|
|
||||||
|
Arena_Kind :: enum uint {
|
||||||
|
Growing = 0, // Chained memory blocks (singly linked list).
|
||||||
|
Static = 1, // Fixed reservation sized.
|
||||||
|
Buffer = 2, // Uses a fixed sized buffer.
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena :: struct {
|
||||||
|
kind: Arena_Kind,
|
||||||
|
curr_block: ^Memory_Block,
|
||||||
|
total_used: uint,
|
||||||
|
total_reserved: uint,
|
||||||
|
minimum_block_size: uint,
|
||||||
|
temp_count: uint,
|
||||||
|
mutex: sync.Mutex,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 1 MiB should be enough to start with
|
||||||
|
DEFAULT_ARENA_STATIC_COMMIT_SIZE :: mem.Megabyte
|
||||||
|
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: DEFAULT_ARENA_STATIC_COMMIT_SIZE
|
||||||
|
|
||||||
|
// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
|
||||||
|
DEFAULT_ARENA_STATIC_RESERVE_SIZE :: mem.Gigabyte when size_of(uintptr) == 8 else 128 * mem.Megabyte
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
||||||
|
arena.kind = .Growing
|
||||||
|
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = arena.curr_block.reserved
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
|
||||||
|
arena.kind = .Static
|
||||||
|
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = arena.curr_block.reserved
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Error) {
|
||||||
|
if len(buffer) < size_of(Memory_Block) {
|
||||||
|
return .Out_Of_Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
arena.kind = .Buffer
|
||||||
|
|
||||||
|
mem.zero_slice(buffer)
|
||||||
|
|
||||||
|
block_base := raw_data(buffer)
|
||||||
|
block := (^Memory_Block)(block_base)
|
||||||
|
block.base = block_base[size_of(Memory_Block):]
|
||||||
|
block.reserved = len(buffer) - size_of(Memory_Block)
|
||||||
|
block.committed = block.reserved
|
||||||
|
block.used = 0
|
||||||
|
|
||||||
|
arena.curr_block = block
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = arena.curr_block.reserved
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||||
|
assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc)
|
||||||
|
|
||||||
|
size := size
|
||||||
|
if size == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
|
switch arena.kind {
|
||||||
|
case .Growing:
|
||||||
|
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
|
||||||
|
size = mem.align_forward_uint(size, alignment)
|
||||||
|
if arena.minimum_block_size == 0 {
|
||||||
|
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
block_size := max(size, arena.minimum_block_size)
|
||||||
|
|
||||||
|
new_block := memory_block_alloc(size, block_size, {}) or_return
|
||||||
|
new_block.prev = arena.curr_block
|
||||||
|
arena.curr_block = new_block
|
||||||
|
arena.total_reserved += new_block.reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
case .Static:
|
||||||
|
if arena.curr_block == nil {
|
||||||
|
if arena.minimum_block_size == 0 {
|
||||||
|
arena.minimum_block_size = DEFAULT_ARENA_STATIC_RESERVE_SIZE
|
||||||
|
}
|
||||||
|
arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case .Buffer:
|
||||||
|
if arena.curr_block == nil {
|
||||||
|
return nil, .Out_Of_Memory
|
||||||
|
}
|
||||||
|
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
|
||||||
|
arena.total_used = arena.curr_block.used
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
|
if arena.curr_block != nil {
|
||||||
|
assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
|
||||||
|
|
||||||
|
prev_pos := arena.curr_block.used
|
||||||
|
arena.curr_block.used = clamp(pos, 0, arena.curr_block.reserved)
|
||||||
|
|
||||||
|
if prev_pos < pos {
|
||||||
|
mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:pos-prev_pos])
|
||||||
|
}
|
||||||
|
arena.total_used = arena.curr_block.used
|
||||||
|
return true
|
||||||
|
} else if pos == 0 {
|
||||||
|
arena.total_used = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
if free_block := arena.curr_block; free_block != nil {
|
||||||
|
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
|
||||||
|
arena.curr_block = free_block.prev
|
||||||
|
memory_block_dealloc(free_block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_free_all :: proc(arena: ^Arena) {
|
||||||
|
switch arena.kind {
|
||||||
|
case .Growing:
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
for arena.curr_block != nil {
|
||||||
|
arena_growing_free_last_memory_block(arena)
|
||||||
|
}
|
||||||
|
arena.total_reserved = 0
|
||||||
|
case .Static, .Buffer:
|
||||||
|
arena_static_reset_to(arena, 0)
|
||||||
|
}
|
||||||
|
arena.total_used = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_destroy :: proc(arena: ^Arena) {
|
||||||
|
arena_free_all(arena)
|
||||||
|
if arena.kind != .Buffer {
|
||||||
|
memory_block_dealloc(arena.curr_block)
|
||||||
|
}
|
||||||
|
arena.curr_block = nil
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = 0
|
||||||
|
arena.temp_count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_growing_bootstrap_new :: proc{
|
||||||
|
arena_growing_bootstrap_new_by_offset,
|
||||||
|
arena_growing_bootstrap_new_by_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_static_bootstrap_new :: proc{
|
||||||
|
arena_static_bootstrap_new_by_offset,
|
||||||
|
arena_static_bootstrap_new_by_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
bootstrap: Arena
|
||||||
|
bootstrap.kind = .Growing
|
||||||
|
bootstrap.minimum_block_size = minimum_block_size
|
||||||
|
|
||||||
|
data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
||||||
|
|
||||||
|
ptr = (^T)(raw_data(data))
|
||||||
|
|
||||||
|
(^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
bootstrap: Arena
|
||||||
|
bootstrap.kind = .Static
|
||||||
|
bootstrap.minimum_block_size = reserved
|
||||||
|
|
||||||
|
data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
||||||
|
|
||||||
|
ptr = (^T)(raw_data(data))
|
||||||
|
|
||||||
|
(^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
|
||||||
|
return mem.Allocator{arena_allocator_proc, arena}
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.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)
|
||||||
|
case .Free:
|
||||||
|
err = .Mode_Not_Implemented
|
||||||
|
case .Free_All:
|
||||||
|
arena_free_all(arena)
|
||||||
|
case .Resize:
|
||||||
|
old_data := ([^]byte)(old_memory)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case old_data == nil:
|
||||||
|
return arena_alloc(arena, size, alignment)
|
||||||
|
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) or_return
|
||||||
|
if new_memory == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(new_memory, old_data[:old_size])
|
||||||
|
return new_memory, nil
|
||||||
|
case .Query_Features:
|
||||||
|
set := (^mem.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)
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
assert(temp.arena != nil, "nil arena", loc)
|
||||||
|
arena := temp.arena
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
|
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_growing_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.reserved-block.used)
|
||||||
|
mem.zero_slice(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
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package mem_virtual
|
|
||||||
|
|
||||||
arena_init :: proc{
|
|
||||||
static_arena_init,
|
|
||||||
growing_arena_init,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_temp_begin :: proc{
|
|
||||||
static_arena_temp_begin,
|
|
||||||
growing_arena_temp_begin,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_temp_end :: proc{
|
|
||||||
static_arena_temp_end,
|
|
||||||
growing_arena_temp_end,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_check_temp :: proc{
|
|
||||||
static_arena_check_temp,
|
|
||||||
growing_arena_check_temp,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_allocator :: proc{
|
|
||||||
static_arena_allocator,
|
|
||||||
growing_arena_allocator,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_alloc :: proc{
|
|
||||||
static_arena_alloc,
|
|
||||||
growing_arena_alloc,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_free_all :: proc{
|
|
||||||
static_arena_free_all,
|
|
||||||
growing_arena_free_all,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_destroy :: proc{
|
|
||||||
static_arena_destroy,
|
|
||||||
growing_arena_destroy,
|
|
||||||
}
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
package mem_virtual
|
|
||||||
|
|
||||||
import "core:mem"
|
|
||||||
|
|
||||||
Growing_Arena :: struct {
|
|
||||||
curr_block: ^Memory_Block,
|
|
||||||
total_used: uint,
|
|
||||||
total_reserved: uint,
|
|
||||||
|
|
||||||
minimum_block_size: uint,
|
|
||||||
temp_count: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
|
|
||||||
|
|
||||||
growing_arena_init :: proc(arena: ^Growing_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
|
||||||
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
|
||||||
arena.total_used = 0
|
|
||||||
arena.total_reserved = arena.curr_block.reserved
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check {
|
|
||||||
alignment_offset := uint(0)
|
|
||||||
ptr := uintptr(arena.curr_block.base[arena.curr_block.used:])
|
|
||||||
mask := uintptr(alignment-1)
|
|
||||||
if ptr & mask != 0 {
|
|
||||||
alignment_offset = uint(alignment) - uint(ptr & mask)
|
|
||||||
}
|
|
||||||
return alignment_offset
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(mem.is_power_of_two(uintptr(alignment)))
|
|
||||||
|
|
||||||
size := uint(0)
|
|
||||||
if arena.curr_block != nil {
|
|
||||||
size = uint(min_size) + align_forward_offset(arena, alignment)
|
|
||||||
}
|
|
||||||
|
|
||||||
if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved {
|
|
||||||
size = uint(mem.align_forward_int(min_size, alignment))
|
|
||||||
arena.minimum_block_size = max(DEFAULT_MINIMUM_BLOCK_SIZE, arena.minimum_block_size)
|
|
||||||
|
|
||||||
block_size := max(size, arena.minimum_block_size)
|
|
||||||
|
|
||||||
new_block := memory_block_alloc(size, block_size, {}) or_return
|
|
||||||
new_block.prev = arena.curr_block
|
|
||||||
arena.curr_block = new_block
|
|
||||||
arena.total_reserved += new_block.reserved
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
data, err = alloc_from_memory_block(arena.curr_block, int(size), alignment)
|
|
||||||
if err == nil {
|
|
||||||
arena.total_used += size
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_free_last_memory_block :: proc(arena: ^Growing_Arena) {
|
|
||||||
free_block := arena.curr_block
|
|
||||||
arena.curr_block = free_block.prev
|
|
||||||
memory_block_dealloc(free_block)
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_free_all :: proc(arena: ^Growing_Arena) {
|
|
||||||
for arena.curr_block != nil {
|
|
||||||
growing_arena_free_last_memory_block(arena)
|
|
||||||
}
|
|
||||||
arena.total_used = 0
|
|
||||||
arena.total_reserved = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_destroy :: proc(arena: ^Growing_Arena) {
|
|
||||||
growing_arena_free_all(arena)
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size := DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
bootstrap: Growing_Arena
|
|
||||||
bootstrap.minimum_block_size = minimum_block_size
|
|
||||||
|
|
||||||
data := growing_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
|
||||||
|
|
||||||
ptr = (^T)(raw_data(data))
|
|
||||||
|
|
||||||
(^Growing_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size := DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
return growing_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
|
|
||||||
}
|
|
||||||
growing_arena_bootstrap_new :: proc{
|
|
||||||
growing_arena_bootstrap_new_by_offset,
|
|
||||||
growing_arena_bootstrap_new_by_name,
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator {
|
|
||||||
return mem.Allocator{growing_arena_allocator_proc, arena}
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|
||||||
size, alignment: int,
|
|
||||||
old_memory: rawptr, old_size: int,
|
|
||||||
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
arena := (^Growing_Arena)(allocator_data)
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case .Alloc:
|
|
||||||
return growing_arena_alloc(arena, size, alignment)
|
|
||||||
case .Free:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
case .Free_All:
|
|
||||||
growing_arena_free_all(arena)
|
|
||||||
return
|
|
||||||
case .Resize:
|
|
||||||
return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, growing_arena_allocator(arena), location)
|
|
||||||
|
|
||||||
case .Query_Features, .Query_Info:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Growing_Arena_Temp :: struct {
|
|
||||||
arena: ^Growing_Arena,
|
|
||||||
block: ^Memory_Block,
|
|
||||||
used: uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_temp_begin :: proc(arena: ^Growing_Arena) -> (temp: Growing_Arena_Temp) {
|
|
||||||
temp.arena = arena
|
|
||||||
temp.block = arena.curr_block
|
|
||||||
if arena.curr_block != nil {
|
|
||||||
temp.used = arena.curr_block.used
|
|
||||||
}
|
|
||||||
arena.temp_count += 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_temp_end :: proc(temp: Growing_Arena_Temp, loc := #caller_location) {
|
|
||||||
assert(temp.arena != nil, "nil arena", loc)
|
|
||||||
arena := temp.arena
|
|
||||||
|
|
||||||
for arena.curr_block != temp.block {
|
|
||||||
growing_arena_free_last_memory_block(arena)
|
|
||||||
}
|
|
||||||
|
|
||||||
if block := arena.curr_block; block != nil {
|
|
||||||
assert(block.used >= temp.used, "out of order use of growing_arena_temp_end", loc)
|
|
||||||
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
|
|
||||||
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
|
||||||
block.used = temp.used
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(arena.temp_count > 0, "double-use of growing_arena_temp_end", loc)
|
|
||||||
arena.temp_count -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_check_temp :: proc(arena: ^Growing_Arena, loc := #caller_location) {
|
|
||||||
assert(arena.temp_count == 0, "Growing_Arena_Temp not been ended", loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
package mem_virtual
|
|
||||||
|
|
||||||
import "core:mem"
|
|
||||||
|
|
||||||
Static_Arena :: struct {
|
|
||||||
block: ^Memory_Block,
|
|
||||||
total_used: uint,
|
|
||||||
total_reserved: uint,
|
|
||||||
|
|
||||||
minimum_block_size: uint,
|
|
||||||
temp_count: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 // 1 MiB should be enough to start with
|
|
||||||
|
|
||||||
// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
|
|
||||||
STATIC_ARENA_DEFAULT_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
|
|
||||||
|
|
||||||
static_arena_init :: proc(arena: ^Static_Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_COMMIT_SIZE) -> (err: Allocator_Error) {
|
|
||||||
arena.block = memory_block_alloc(commit_size, reserved, {}) or_return
|
|
||||||
arena.total_used = 0
|
|
||||||
arena.total_reserved = arena.block.reserved
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_destroy :: proc(arena: ^Static_Arena) {
|
|
||||||
memory_block_dealloc(arena.block)
|
|
||||||
arena^ = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_alloc :: proc(arena: ^Static_Arena, size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
align_forward :: #force_inline proc "contextless" (ptr: uint, align: uint) -> uint {
|
|
||||||
mask := align-1
|
|
||||||
return (ptr + mask) &~ mask
|
|
||||||
}
|
|
||||||
|
|
||||||
if arena.block == nil {
|
|
||||||
reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE)
|
|
||||||
static_arena_init(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return
|
|
||||||
}
|
|
||||||
|
|
||||||
MINIMUM_ALIGN :: 2*align_of(uintptr)
|
|
||||||
|
|
||||||
defer arena.total_used = arena.block.used
|
|
||||||
return alloc_from_memory_block(arena.block, size, max(MINIMUM_ALIGN, alignment))
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_reset_to :: proc(arena: ^Static_Arena, pos: uint) -> bool {
|
|
||||||
if arena.block != nil {
|
|
||||||
prev_pos := arena.block.used
|
|
||||||
arena.block.used = clamp(pos, 0, arena.block.reserved)
|
|
||||||
|
|
||||||
if prev_pos < pos {
|
|
||||||
mem.zero_slice(arena.block.base[arena.block.used:][:pos-prev_pos])
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} else if pos == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_free_all :: proc(arena: ^Static_Arena) {
|
|
||||||
static_arena_reset_to(arena, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
bootstrap: Static_Arena
|
|
||||||
bootstrap.minimum_block_size = reserved
|
|
||||||
|
|
||||||
data := static_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
|
||||||
|
|
||||||
ptr = (^T)(raw_data(data))
|
|
||||||
|
|
||||||
(^Static_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
return static_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
|
|
||||||
}
|
|
||||||
static_arena_bootstrap_new :: proc{
|
|
||||||
static_arena_bootstrap_new_by_offset,
|
|
||||||
static_arena_bootstrap_new_by_name,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_allocator :: proc(arena: ^Static_Arena) -> mem.Allocator {
|
|
||||||
return mem.Allocator{static_arena_allocator_proc, arena}
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|
||||||
size, alignment: int,
|
|
||||||
old_memory: rawptr, old_size: int,
|
|
||||||
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
arena := (^Static_Arena)(allocator_data)
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case .Alloc:
|
|
||||||
return static_arena_alloc(arena, size, alignment)
|
|
||||||
case .Free:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
case .Free_All:
|
|
||||||
static_arena_free_all(arena)
|
|
||||||
return
|
|
||||||
case .Resize:
|
|
||||||
return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, static_arena_allocator(arena), location)
|
|
||||||
|
|
||||||
case .Query_Features, .Query_Info:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Static_Arena_Temp :: struct {
|
|
||||||
arena: ^Static_Arena,
|
|
||||||
used: uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_temp_begin :: proc(arena: ^Static_Arena) -> (temp: Static_Arena_Temp) {
|
|
||||||
temp.arena = arena
|
|
||||||
temp.used = arena.block.used if arena.block != nil else 0
|
|
||||||
arena.temp_count += 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_temp_end :: proc(temp: Static_Arena_Temp, loc := #caller_location) {
|
|
||||||
assert(temp.arena != nil, "nil arena", loc)
|
|
||||||
arena := temp.arena
|
|
||||||
|
|
||||||
used := arena.block.used if arena.block != nil else 0
|
|
||||||
|
|
||||||
assert(temp.used >= used, "invalid Static_Arena_Temp", loc)
|
|
||||||
|
|
||||||
static_arena_reset_to(arena, temp.used)
|
|
||||||
|
|
||||||
assert(arena.temp_count > 0, "double-use of static_arena_temp_end", loc)
|
|
||||||
arena.temp_count -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_check_temp :: proc(arena: ^Static_Arena, loc := #caller_location) {
|
|
||||||
assert(arena.temp_count == 0, "Static_Arena_Temp not been ended", loc)
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
package mem_virtual
|
package mem_virtual
|
||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
DEFAULT_PAGE_SIZE := uint(4096)
|
DEFAULT_PAGE_SIZE := uint(4096)
|
||||||
|
|
||||||
Allocator_Error :: mem.Allocator_Error
|
Allocator_Error :: mem.Allocator_Error
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
return _reserve(size)
|
return _reserve(size)
|
||||||
}
|
}
|
||||||
@@ -14,6 +16,7 @@ commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
|||||||
return _commit(data, size)
|
return _commit(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
data = reserve(size) or_return
|
data = reserve(size) or_return
|
||||||
commit(raw_data(data), size) or_return
|
commit(raw_data(data), size) or_return
|
||||||
@@ -56,6 +59,7 @@ Memory_Block_Flag :: enum u32 {
|
|||||||
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
|
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
|
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||||
align_formula :: proc "contextless" (size, align: uint) -> uint {
|
align_formula :: proc "contextless" (size, align: uint) -> uint {
|
||||||
result := size + align-1
|
result := size + align-1
|
||||||
@@ -95,18 +99,12 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
|||||||
pmblock.block.committed = committed
|
pmblock.block.committed = committed
|
||||||
pmblock.block.reserved = reserved
|
pmblock.block.reserved = reserved
|
||||||
|
|
||||||
sentinel := &global_platform_memory_block_sentinel
|
|
||||||
platform_mutex_lock()
|
|
||||||
pmblock.next = sentinel
|
|
||||||
pmblock.prev = sentinel.prev
|
|
||||||
pmblock.prev.next = pmblock
|
|
||||||
pmblock.next.prev = pmblock
|
|
||||||
platform_mutex_unlock()
|
|
||||||
|
|
||||||
return &pmblock.block, nil
|
return &pmblock.block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
@(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 {
|
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||||
alignment_offset := uint(0)
|
alignment_offset := uint(0)
|
||||||
ptr := uintptr(block.base[block.used:])
|
ptr := uintptr(block.base[block.used:])
|
||||||
@@ -134,11 +132,18 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if block == nil {
|
||||||
|
return nil, .Out_Of_Memory
|
||||||
|
}
|
||||||
|
|
||||||
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
||||||
size := uint(min_size) + alignment_offset
|
size, size_ok := safe_add(min_size, alignment_offset)
|
||||||
|
if !size_ok {
|
||||||
|
err = .Out_Of_Memory
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if block.used + size > block.reserved {
|
if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.reserved {
|
||||||
err = .Out_Of_Memory
|
err = .Out_Of_Memory
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -153,12 +158,14 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
|
|||||||
|
|
||||||
memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
|
memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
|
||||||
if block := (^Platform_Memory_Block)(block_to_free); block != nil {
|
if block := (^Platform_Memory_Block)(block_to_free); block != nil {
|
||||||
platform_mutex_lock()
|
|
||||||
block.prev.next = block.next
|
|
||||||
block.next.prev = block.prev
|
|
||||||
platform_mutex_unlock()
|
|
||||||
|
|
||||||
platform_memory_free(block)
|
platform_memory_free(block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(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
|
||||||
|
}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
//+private
|
//+private
|
||||||
package mem_virtual
|
package mem_virtual
|
||||||
|
|
||||||
import "core:sync"
|
|
||||||
|
|
||||||
Platform_Memory_Block :: struct {
|
Platform_Memory_Block :: struct {
|
||||||
block: Memory_Block,
|
block: Memory_Block,
|
||||||
committed: uint,
|
committed: uint,
|
||||||
reserved: uint,
|
reserved: uint,
|
||||||
prev, next: ^Platform_Memory_Block,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
||||||
@@ -33,28 +30,6 @@ platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_mutex_lock :: proc() {
|
|
||||||
sync.mutex_lock(&global_memory_block_mutex)
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_mutex_unlock :: proc() {
|
|
||||||
sync.mutex_unlock(&global_memory_block_mutex)
|
|
||||||
}
|
|
||||||
|
|
||||||
global_memory_block_mutex: sync.Mutex
|
|
||||||
global_platform_memory_block_sentinel: Platform_Memory_Block
|
|
||||||
global_platform_memory_block_sentinel_set: bool
|
|
||||||
|
|
||||||
@(init)
|
|
||||||
platform_memory_init :: proc() {
|
|
||||||
if !global_platform_memory_block_sentinel_set {
|
|
||||||
_platform_memory_init()
|
|
||||||
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel
|
|
||||||
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel
|
|
||||||
global_platform_memory_block_sentinel_set = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
|
platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
|
||||||
if to_commit < block.committed {
|
if to_commit < block.committed {
|
||||||
return nil
|
return nil
|
||||||
@@ -63,7 +38,6 @@ platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_
|
|||||||
return .Out_Of_Memory
|
return .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
commit(block, to_commit) or_return
|
commit(block, to_commit) or_return
|
||||||
block.committed = to_commit
|
block.committed = to_commit
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
|||||||
|
|
||||||
dirpath: string
|
dirpath: string
|
||||||
dirpath, err = absolute_path_from_handle(fd)
|
dirpath, err = absolute_path_from_handle(fd)
|
||||||
|
|
||||||
if err != ERROR_NONE {
|
if err != ERROR_NONE {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer delete(dirpath)
|
||||||
|
|
||||||
n := n
|
n := n
|
||||||
size := n
|
size := n
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package os
|
|||||||
|
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:time"
|
|
||||||
|
|
||||||
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||||
find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
|
find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
|
||||||
@@ -41,9 +40,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
|||||||
// fi.mode |= file_type_mode(h);
|
// fi.mode |= file_type_mode(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
windows_set_file_info_times(&fi, d)
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
|
||||||
|
|
||||||
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -162,7 +162,8 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
|||||||
total_read: int
|
total_read: int
|
||||||
length := len(data)
|
length := len(data)
|
||||||
|
|
||||||
to_read := min(win32.DWORD(length), MAX_RW)
|
// NOTE(Jeroen): `length` can't be casted to win32.DWORD here because it'll overflow if > 4 GiB and return 0 if exactly that.
|
||||||
|
to_read := min(i64(length), MAX_RW)
|
||||||
|
|
||||||
e: win32.BOOL
|
e: win32.BOOL
|
||||||
if is_console {
|
if is_console {
|
||||||
@@ -172,7 +173,8 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
|||||||
return int(total_read), err
|
return int(total_read), err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
e = win32.ReadFile(handle, &data[total_read], to_read, &single_read_length, nil)
|
// NOTE(Jeroen): So we cast it here *after* we've ensured that `to_read` is at most MAX_RW (1 GiB)
|
||||||
|
e = win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &single_read_length, nil)
|
||||||
}
|
}
|
||||||
if single_read_length <= 0 || !e {
|
if single_read_length <= 0 || !e {
|
||||||
err := Errno(win32.GetLastError())
|
err := Errno(win32.GetLastError())
|
||||||
|
|||||||
+14
-10
@@ -93,7 +93,7 @@ file_size_from_path :: proc(path: string) -> i64 {
|
|||||||
return length
|
return length
|
||||||
}
|
}
|
||||||
|
|
||||||
read_entire_file_from_filename :: proc(name: string, allocator := context.allocator) -> (data: []byte, success: bool) {
|
read_entire_file_from_filename :: proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
fd, err := open(name, O_RDONLY, 0)
|
fd, err := open(name, O_RDONLY, 0)
|
||||||
@@ -102,10 +102,10 @@ read_entire_file_from_filename :: proc(name: string, allocator := context.alloca
|
|||||||
}
|
}
|
||||||
defer close(fd)
|
defer close(fd)
|
||||||
|
|
||||||
return read_entire_file_from_handle(fd, allocator)
|
return read_entire_file_from_handle(fd, allocator, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator) -> (data: []byte, success: bool) {
|
read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
length: i64
|
length: i64
|
||||||
@@ -118,7 +118,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
|
|||||||
return nil, true
|
return nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
data = make([]byte, int(length), allocator)
|
data = make([]byte, int(length), allocator, loc)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
// the pointer we return to the user.
|
// the pointer we return to the user.
|
||||||
//
|
//
|
||||||
|
|
||||||
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
|
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil, zero_memory := true) -> ([]byte, mem.Allocator_Error) {
|
||||||
a := max(alignment, align_of(rawptr))
|
a := max(alignment, align_of(rawptr))
|
||||||
space := size + a - 1
|
space := size + a - 1
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
|
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
||||||
} else {
|
} else {
|
||||||
allocated_mem = heap_alloc(space+size_of(rawptr))
|
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
|
||||||
}
|
}
|
||||||
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
new_memory = aligned_alloc(new_size, new_alignment, p) or_return
|
new_memory = aligned_alloc(new_size, new_alignment, p) or_return
|
||||||
|
|
||||||
// NOTE: heap_resize does not zero the new memory, so we do it
|
// NOTE: heap_resize does not zero the new memory, so we do it
|
||||||
if new_size > old_size {
|
if new_size > old_size {
|
||||||
new_region := mem.raw_data(new_memory[old_size:])
|
new_region := mem.raw_data(new_memory[old_size:])
|
||||||
@@ -226,8 +226,8 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return aligned_alloc(size, alignment)
|
return aligned_alloc(size, alignment, nil, mode == .Alloc)
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
aligned_free(old_memory)
|
aligned_free(old_memory)
|
||||||
@@ -244,7 +244,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^mem.Allocator_Mode_Set)(old_memory)
|
set := (^mem.Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
@@ -261,3 +261,7 @@ heap_allocator :: proc() -> mem.Allocator {
|
|||||||
data = nil,
|
data = nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processor_core_count :: proc() -> int {
|
||||||
|
return _processor_core_count()
|
||||||
|
}
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ _new_file :: proc(handle: uintptr, name: string) -> ^File {
|
|||||||
f := new(File, _file_allocator())
|
f := new(File, _file_allocator())
|
||||||
|
|
||||||
f.impl.allocator = _file_allocator()
|
f.impl.allocator = _file_allocator()
|
||||||
f.impl.fd = rawptr(fd)
|
f.impl.fd = rawptr(handle)
|
||||||
f.impl.name = strings.clone(name, f.impl.allocator)
|
f.impl.name = strings.clone(name, f.impl.allocator)
|
||||||
f.impl.wname = win32.utf8_to_wstring(name, f.impl.allocator)
|
f.impl.wname = win32.utf8_to_wstring(name, f.impl.allocator)
|
||||||
|
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return aligned_alloc(size, alignment)
|
return aligned_alloc(size, alignment)
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ package os2
|
|||||||
import "core:mem"
|
import "core:mem"
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory: bool) -> rawptr {
|
||||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, uint(size))
|
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY if zero_memory else 0, uint(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int, zero_memory: bool) -> rawptr {
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
heap_free(ptr)
|
heap_free(ptr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if ptr == nil {
|
if ptr == nil {
|
||||||
return heap_alloc(new_size)
|
return heap_alloc(new_size, zero_memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, uint(new_size))
|
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, uint(new_size))
|
||||||
@@ -36,16 +36,16 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
// the pointer we return to the user.
|
// the pointer we return to the user.
|
||||||
//
|
//
|
||||||
|
|
||||||
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
|
aligned_alloc :: proc(size, alignment: int, zero_memory: bool, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
|
||||||
a := max(alignment, align_of(rawptr))
|
a := max(alignment, align_of(rawptr))
|
||||||
space := size + a - 1
|
space := size + a - 1
|
||||||
|
|
||||||
allocated_mem: rawptr
|
allocated_mem: rawptr
|
||||||
if old_ptr != nil {
|
if old_ptr != nil {
|
||||||
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
|
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr), zero_memory)
|
||||||
} else {
|
} else {
|
||||||
allocated_mem = heap_alloc(space+size_of(rawptr))
|
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
|
||||||
}
|
}
|
||||||
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||||
|
|
||||||
@@ -72,12 +72,12 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return aligned_alloc(new_size, new_alignment, p)
|
return aligned_alloc(new_size, new_alignment, true, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return aligned_alloc(size, alignment)
|
return aligned_alloc(size, alignment, mode == .Alloc)
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
aligned_free(old_memory)
|
aligned_free(old_memory)
|
||||||
@@ -87,7 +87,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
|
|
||||||
case .Resize:
|
case .Resize:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return aligned_alloc(size, alignment)
|
return aligned_alloc(size, alignment, true)
|
||||||
}
|
}
|
||||||
return aligned_resize(old_memory, old_size, size, alignment)
|
return aligned_resize(old_memory, old_size, size, alignment)
|
||||||
|
|
||||||
|
|||||||
+44
-9
@@ -314,6 +314,7 @@ foreign libc {
|
|||||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||||
|
|
||||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||||
|
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||||
|
|
||||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
@@ -333,7 +334,7 @@ foreign dl {
|
|||||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __error()^
|
return __error()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,21 +343,33 @@ get_last_error_string :: proc() -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
||||||
|
isDir := is_dir_path(path)
|
||||||
|
flags := flags
|
||||||
|
if isDir {
|
||||||
|
/*
|
||||||
|
@INFO(Platin): To make it impossible to use the wrong flag for dir's
|
||||||
|
as you can't write to a dir only read which makes it fail to open
|
||||||
|
*/
|
||||||
|
flags = O_RDONLY
|
||||||
|
}
|
||||||
|
|
||||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||||
if handle == -1 {
|
if handle == -1 {
|
||||||
return INVALID_HANDLE, 1
|
return INVALID_HANDLE, cast(Errno)get_last_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
|
/*
|
||||||
if mode != 0 {
|
@INFO(Platin): this is only done because O_CREATE for some reason fails to apply mode
|
||||||
|
should not happen if the handle is a directory
|
||||||
|
*/
|
||||||
|
if mode != 0 && !isDir {
|
||||||
err := fchmod(handle, cast(u16)mode)
|
err := fchmod(handle, cast(u16)mode)
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
_unix_close(handle)
|
_unix_close(handle)
|
||||||
return INVALID_HANDLE, 1
|
return INVALID_HANDLE, cast(Errno)err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return handle, 0
|
return handle, 0
|
||||||
}
|
}
|
||||||
@@ -404,6 +417,9 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
|||||||
if bytes_read == -1 {
|
if bytes_read == -1 {
|
||||||
return bytes_read_total, 1
|
return bytes_read_total, 1
|
||||||
}
|
}
|
||||||
|
if bytes_read == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
bytes_read_total += bytes_read
|
bytes_read_total += bytes_read
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,9 +659,15 @@ access :: proc(path: string, mask: int) -> bool {
|
|||||||
return _unix_access(cstr, mask) == 0
|
return _unix_access(cstr, mask) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
assert(size > 0)
|
if size <= 0 {
|
||||||
return _unix_calloc(1, size)
|
return nil
|
||||||
|
}
|
||||||
|
if zero_memory {
|
||||||
|
return _unix_calloc(1, size)
|
||||||
|
} else {
|
||||||
|
return _unix_malloc(size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||||
@@ -679,6 +701,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return string(cwd)
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size)
|
resize(&buf, len(buf)+page_size)
|
||||||
@@ -750,6 +773,18 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
count : int = 0
|
||||||
|
count_size := size_of(count)
|
||||||
|
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
|
||||||
|
if count > 0 {
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ current_thread_id :: proc "contextless" () -> int {
|
|||||||
return (int) (es.ThreadGetID(es.CURRENT_THREAD));
|
return (int) (es.ThreadGetID(es.CURRENT_THREAD));
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
return es.HeapAllocate(size, false);
|
return es.HeapAllocate(size, zero_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_free :: proc(ptr: rawptr) {
|
heap_free :: proc(ptr: rawptr) {
|
||||||
|
|||||||
+25
-4
@@ -287,6 +287,7 @@ foreign libc {
|
|||||||
|
|
||||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||||
|
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||||
|
|
||||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
@@ -303,7 +304,7 @@ is_path_separator :: proc(r: rune) -> bool {
|
|||||||
return r == '/'
|
return r == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __errno_location()^
|
return __errno_location()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,9 +604,15 @@ access :: proc(path: string, mask: int) -> (bool, Errno) {
|
|||||||
return true, ERROR_NONE
|
return true, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
assert(size >= 0)
|
if size <= 0 {
|
||||||
return _unix_calloc(1, c.size_t(size))
|
return nil
|
||||||
|
}
|
||||||
|
if zero_memory {
|
||||||
|
return _unix_calloc(1, c.size_t(size))
|
||||||
|
} else {
|
||||||
|
return _unix_malloc(c.size_t(size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
@@ -644,6 +651,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return string(cwd)
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size)
|
resize(&buf, len(buf)+page_size)
|
||||||
@@ -696,6 +704,19 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
count : int = 0
|
||||||
|
count_size := size_of(count)
|
||||||
|
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
|
||||||
|
if count > 0 {
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
+16
-4
@@ -404,6 +404,7 @@ foreign libc {
|
|||||||
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
||||||
|
|
||||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||||
|
@(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int ---
|
||||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
@@ -441,7 +442,7 @@ _get_errno :: proc(res: int) -> Errno {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get errno from libc
|
// get errno from libc
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __errno_location()^
|
return __errno_location()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,9 +756,15 @@ access :: proc(path: string, mask: int) -> (bool, Errno) {
|
|||||||
return true, ERROR_NONE
|
return true, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
assert(size >= 0)
|
if size <= 0 {
|
||||||
return _unix_calloc(1, c.size_t(size))
|
return nil
|
||||||
|
}
|
||||||
|
if zero_memory {
|
||||||
|
return _unix_calloc(1, c.size_t(size))
|
||||||
|
} else {
|
||||||
|
return _unix_malloc(c.size_t(size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
@@ -816,6 +823,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
|
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
|
||||||
}
|
}
|
||||||
if _get_errno(res) != ERANGE {
|
if _get_errno(res) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size)
|
resize(&buf, len(buf)+page_size)
|
||||||
@@ -872,6 +880,10 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
return int(_unix_get_nprocs())
|
||||||
|
}
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
+19
-5
@@ -269,6 +269,7 @@ foreign libc {
|
|||||||
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||||
|
|
||||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||||
|
@(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
|
||||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
@@ -294,7 +295,7 @@ is_path_separator :: proc(r: rune) -> bool {
|
|||||||
return r == '/'
|
return r == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __errno()^
|
return __errno()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,9 +606,15 @@ access :: proc(path: string, mask: int) -> (bool, Errno) {
|
|||||||
return true, ERROR_NONE
|
return true, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
assert(size >= 0)
|
if size <= 0 {
|
||||||
return _unix_calloc(1, c.size_t(size))
|
return nil
|
||||||
|
}
|
||||||
|
if zero_memory {
|
||||||
|
return _unix_calloc(1, c.size_t(size))
|
||||||
|
} else {
|
||||||
|
return _unix_malloc(c.size_t(size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
@@ -642,6 +649,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return string(cwd)
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf) + MAX_PATH)
|
resize(&buf, len(buf) + MAX_PATH)
|
||||||
@@ -698,6 +706,12 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_SC_NPROCESSORS_ONLN :: 503
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
return int(_sysconf(_SC_NPROCESSORS_ONLN))
|
||||||
|
}
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
@@ -705,4 +719,4 @@ _alloc_command_line_arguments :: proc() -> []string {
|
|||||||
res[i] = string(arg)
|
res[i] = string(arg)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-5
@@ -24,7 +24,7 @@ O_CLOEXEC :: 0x80000
|
|||||||
stdin: Handle = 0
|
stdin: Handle = 0
|
||||||
stdout: Handle = 1
|
stdout: Handle = 1
|
||||||
stderr: Handle = 2
|
stderr: Handle = 2
|
||||||
|
current_dir: Handle = 3
|
||||||
|
|
||||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
iovs := wasi.ciovec_t(data)
|
iovs := wasi.ciovec_t(data)
|
||||||
@@ -47,7 +47,36 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
|
|||||||
return int(n), Errno(err)
|
return int(n), Errno(err)
|
||||||
}
|
}
|
||||||
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) {
|
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) {
|
||||||
return 0, -1
|
oflags: wasi.oflags_t
|
||||||
|
if mode & O_CREATE == O_CREATE {
|
||||||
|
oflags += {.CREATE}
|
||||||
|
}
|
||||||
|
if mode & O_EXCL == O_EXCL {
|
||||||
|
oflags += {.EXCL}
|
||||||
|
}
|
||||||
|
if mode & O_TRUNC == O_TRUNC {
|
||||||
|
oflags += {.TRUNC}
|
||||||
|
}
|
||||||
|
|
||||||
|
rights: wasi.rights_t = {.FD_SEEK, .FD_FILESTAT_GET}
|
||||||
|
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
||||||
|
case O_RDONLY: rights += {.FD_READ}
|
||||||
|
case O_WRONLY: rights += {.FD_WRITE}
|
||||||
|
case O_RDWR: rights += {.FD_READ, .FD_WRITE}
|
||||||
|
}
|
||||||
|
|
||||||
|
fdflags: wasi.fdflags_t
|
||||||
|
if mode & O_APPEND == O_APPEND {
|
||||||
|
fdflags += {.APPEND}
|
||||||
|
}
|
||||||
|
if mode & O_NONBLOCK == O_NONBLOCK {
|
||||||
|
fdflags += {.NONBLOCK}
|
||||||
|
}
|
||||||
|
if mode & O_SYNC == O_SYNC {
|
||||||
|
fdflags += {.SYNC}
|
||||||
|
}
|
||||||
|
fd, err := wasi.path_open(wasi.fd_t(current_dir),{.SYMLINK_FOLLOW},path,oflags,rights,{},fdflags)
|
||||||
|
return Handle(fd), Errno(err)
|
||||||
}
|
}
|
||||||
close :: proc(fd: Handle) -> Errno {
|
close :: proc(fd: Handle) -> Errno {
|
||||||
err := wasi.fd_close(wasi.fd_t(fd))
|
err := wasi.fd_close(wasi.fd_t(fd))
|
||||||
@@ -60,7 +89,10 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
|||||||
current_thread_id :: proc "contextless" () -> int {
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||||
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
|
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
|
||||||
@@ -72,7 +104,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
@@ -96,4 +128,4 @@ heap_free :: proc(ptr: rawptr) {
|
|||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
runtime._cleanup_runtime_contextless()
|
runtime._cleanup_runtime_contextless()
|
||||||
wasi.proc_exit(wasi.exitcode_t(code))
|
wasi.proc_exit(wasi.exitcode_t(code))
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-3
@@ -3,6 +3,7 @@ package os
|
|||||||
|
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
Handle :: distinct uintptr
|
Handle :: distinct uintptr
|
||||||
File_Time :: distinct u64
|
File_Time :: distinct u64
|
||||||
@@ -91,8 +92,8 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
|
||||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, uint(size))
|
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY if zero_memory else 0, uint(size))
|
||||||
}
|
}
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
@@ -126,7 +127,28 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
length : win32.DWORD = 0
|
||||||
|
result := win32.GetLogicalProcessorInformation(nil, &length)
|
||||||
|
|
||||||
|
thread_count := 0
|
||||||
|
if !result && win32.GetLastError() == 122 && length > 0 {
|
||||||
|
processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator)
|
||||||
|
|
||||||
|
result = win32.GetLogicalProcessorInformation(&processors[0], &length)
|
||||||
|
if result {
|
||||||
|
for processor in processors {
|
||||||
|
if processor.Relationship == .RelationProcessorCore {
|
||||||
|
thread := intrinsics.count_ones(processor.ProcessorMask)
|
||||||
|
thread_count += int(thread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thread_count
|
||||||
|
}
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
runtime._cleanup_runtime_contextless()
|
runtime._cleanup_runtime_contextless()
|
||||||
@@ -214,4 +236,4 @@ is_windows_10 :: proc() -> bool {
|
|||||||
is_windows_11 :: proc() -> bool {
|
is_windows_11 :: proc() -> bool {
|
||||||
osvi := get_windows_version_w()
|
osvi := get_windows_version_w()
|
||||||
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
|
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -228,6 +228,13 @@ file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HAN
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) {
|
||||||
|
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||||
|
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||||
|
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||||
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) {
|
file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) {
|
||||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
||||||
@@ -235,9 +242,7 @@ file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_
|
|||||||
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||||
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
windows_set_file_info_times(&fi, d)
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
|
||||||
|
|
||||||
fi.fullpath, e = full_path_from_name(name)
|
fi.fullpath, e = full_path_from_name(name)
|
||||||
fi.name = basename(fi.fullpath)
|
fi.name = basename(fi.fullpath)
|
||||||
@@ -252,9 +257,7 @@ file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string)
|
|||||||
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||||
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
windows_set_file_info_times(&fi, d)
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
|
||||||
|
|
||||||
fi.fullpath, e = full_path_from_name(name)
|
fi.fullpath, e = full_path_from_name(name)
|
||||||
fi.name = basename(fi.fullpath)
|
fi.name = basename(fi.fullpath)
|
||||||
@@ -290,10 +293,7 @@ file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HAN
|
|||||||
fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
|
fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
|
||||||
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
fi.is_dir = fi.mode & File_Mode_Dir != 0
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
windows_set_file_info_times(&fi, &d)
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
|
||||||
|
|
||||||
|
|
||||||
return fi, ERROR_NONE
|
return fi, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import "core:slice"
|
|||||||
// The sole exception is if 'skip_dir' is returned as true:
|
// The sole exception is if 'skip_dir' is returned as true:
|
||||||
// when 'skip_dir' is invoked on a directory. 'walk' skips directory contents
|
// when 'skip_dir' is invoked on a directory. 'walk' skips directory contents
|
||||||
// when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory
|
// when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory
|
||||||
Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool)
|
Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno, user_data: rawptr) -> (err: os.Errno, skip_dir: bool)
|
||||||
|
|
||||||
// walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root'
|
// walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root'
|
||||||
// All errors that happen visiting files and directories are filtered by walk_proc
|
// All errors that happen visiting files and directories are filtered by walk_proc
|
||||||
@@ -22,28 +22,28 @@ Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno,
|
|||||||
// NOTE: Walking large directories can be inefficient due to the lexical sort
|
// NOTE: Walking large directories can be inefficient due to the lexical sort
|
||||||
// NOTE: walk does not follow symbolic links
|
// NOTE: walk does not follow symbolic links
|
||||||
// NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done
|
// NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done
|
||||||
walk :: proc(root: string, walk_proc: Walk_Proc) -> os.Errno {
|
walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Errno {
|
||||||
info, err := os.lstat(root, context.temp_allocator)
|
info, err := os.lstat(root, context.temp_allocator)
|
||||||
defer os.file_info_delete(info, context.temp_allocator)
|
defer os.file_info_delete(info, context.temp_allocator)
|
||||||
|
|
||||||
skip_dir: bool
|
skip_dir: bool
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
err, skip_dir = walk_proc(info, err)
|
err, skip_dir = walk_proc(info, err, user_data)
|
||||||
} else {
|
} else {
|
||||||
err, skip_dir = _walk(info, walk_proc)
|
err, skip_dir = _walk(info, walk_proc, user_data)
|
||||||
}
|
}
|
||||||
return 0 if skip_dir else err
|
return 0 if skip_dir else err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc) -> (err: os.Errno, skip_dir: bool) {
|
_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Errno, skip_dir: bool) {
|
||||||
if !info.is_dir {
|
if !info.is_dir {
|
||||||
if info.fullpath == "" && info.name == "" {
|
if info.fullpath == "" && info.name == "" {
|
||||||
// ignore empty things
|
// ignore empty things
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return walk_proc(info, 0)
|
return walk_proc(info, 0, user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fis: []os.File_Info
|
fis: []os.File_Info
|
||||||
@@ -51,14 +51,14 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc) -> (err: os.Errno, skip_
|
|||||||
fis, err = read_dir(info.fullpath, context.temp_allocator)
|
fis, err = read_dir(info.fullpath, context.temp_allocator)
|
||||||
defer os.file_info_slice_delete(fis, context.temp_allocator)
|
defer os.file_info_slice_delete(fis, context.temp_allocator)
|
||||||
|
|
||||||
err1, skip_dir = walk_proc(info, err)
|
err1, skip_dir = walk_proc(info, err, user_data)
|
||||||
if err != 0 || err1 != 0 || skip_dir {
|
if err != 0 || err1 != 0 || skip_dir {
|
||||||
err = err1
|
err = err1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for fi in fis {
|
for fi in fis {
|
||||||
err, skip_dir = _walk(fi, walk_proc)
|
err, skip_dir = _walk(fi, walk_proc, user_data)
|
||||||
if err != 0 || skip_dir {
|
if err != 0 || skip_dir {
|
||||||
if !fi.is_dir || !skip_dir {
|
if !fi.is_dir || !skip_dir {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package reflect
|
||||||
|
|
||||||
|
import "core:runtime"
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
||||||
|
if val == nil || it == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ti := type_info_base(type_info_of(val.id))
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_Pointer:
|
||||||
|
if ptr := (^rawptr)(val.data)^; ptr != nil {
|
||||||
|
return iterate_array(any{ptr, info.elem.id}, it)
|
||||||
|
}
|
||||||
|
case Type_Info_Array:
|
||||||
|
if it^ < info.count {
|
||||||
|
elem.data = rawptr(uintptr(val.data) + uintptr(it^ * info.elem_size))
|
||||||
|
elem.id = info.elem.id
|
||||||
|
ok = true
|
||||||
|
it^ += 1
|
||||||
|
}
|
||||||
|
case Type_Info_Slice:
|
||||||
|
array := (^runtime.Raw_Slice)(val.data)
|
||||||
|
if it^ < array.len {
|
||||||
|
elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size))
|
||||||
|
elem.id = info.elem.id
|
||||||
|
ok = true
|
||||||
|
it^ += 1
|
||||||
|
}
|
||||||
|
case Type_Info_Dynamic_Array:
|
||||||
|
array := (^runtime.Raw_Dynamic_Array)(val.data)
|
||||||
|
if it^ < array.len {
|
||||||
|
elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size))
|
||||||
|
elem.id = info.elem.id
|
||||||
|
ok = true
|
||||||
|
it^ += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
|
||||||
|
if val == nil || it == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ti := type_info_base(type_info_of(val.id))
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_Pointer:
|
||||||
|
if ptr := (^rawptr)(val.data)^; ptr != nil {
|
||||||
|
return iterate_map(any{ptr, info.elem.id}, it)
|
||||||
|
}
|
||||||
|
case Type_Info_Map:
|
||||||
|
if info.map_info == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rm := (^runtime.Raw_Map)(val.data)
|
||||||
|
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(rm^, info.map_info)
|
||||||
|
for /**/ ; it^ < int(runtime.map_cap(rm^)); it^ += 1 {
|
||||||
|
if hash := hs[it^]; runtime.map_hash_is_valid(hash) {
|
||||||
|
key_ptr := runtime.map_cell_index_dynamic(ks, info.map_info.ks, uintptr(it^))
|
||||||
|
value_ptr := runtime.map_cell_index_dynamic(vs, info.map_info.vs, uintptr(it^))
|
||||||
|
|
||||||
|
key.data = rawptr(key_ptr)
|
||||||
|
value.data = rawptr(value_ptr)
|
||||||
|
key.id = info.key.id
|
||||||
|
value.id = info.value.id
|
||||||
|
ok = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package reflect
|
|
||||||
|
|
||||||
import "core:runtime"
|
|
||||||
import "core:mem"
|
|
||||||
_ :: runtime
|
|
||||||
_ :: mem
|
|
||||||
|
|
||||||
Map_Entry_Info :: struct($Key, $Value: typeid) {
|
|
||||||
hash: uintptr,
|
|
||||||
key: Key,
|
|
||||||
value: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
map_entry_info_slice :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry_Info(K, V)) #no_bounds_check {
|
|
||||||
m := m
|
|
||||||
rm := (^mem.Raw_Map)(&m)
|
|
||||||
|
|
||||||
info := type_info_base(type_info_of(M)).variant.(Type_Info_Map)
|
|
||||||
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct)
|
|
||||||
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array)
|
|
||||||
entry_type := ed.elem.variant.(Type_Info_Struct)
|
|
||||||
key_offset := entry_type.offsets[2]
|
|
||||||
value_offset := entry_type.offsets[3]
|
|
||||||
entry_size := uintptr(ed.elem_size)
|
|
||||||
|
|
||||||
entries = make(type_of(entries), rm.entries.len)
|
|
||||||
|
|
||||||
data := uintptr(rm.entries.data)
|
|
||||||
for i in 0..<rm.entries.len {
|
|
||||||
header := (^runtime.Map_Entry_Header)(data)
|
|
||||||
|
|
||||||
hash := header.hash
|
|
||||||
key := (^K)(data + key_offset)^
|
|
||||||
value := (^V)(data + value_offset)^
|
|
||||||
|
|
||||||
entries[i] = {hash, key, value}
|
|
||||||
|
|
||||||
data += entry_size
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
+63
-41
@@ -74,6 +74,7 @@ Type_Kind :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
type_kind :: proc(T: typeid) -> Type_Kind {
|
type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
ti := type_info_of(T)
|
ti := type_info_of(T)
|
||||||
if ti != nil {
|
if ti != nil {
|
||||||
@@ -113,57 +114,31 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bill): Better name
|
// TODO(bill): Better name
|
||||||
|
@(require_results)
|
||||||
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
return type_kind(runtime.typeid_base(T))
|
return type_kind(runtime.typeid_base(T))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bill): Better name
|
// TODO(bill): Better name
|
||||||
|
@(require_results)
|
||||||
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
return type_kind(runtime.typeid_core(T))
|
return type_kind(runtime.typeid_core(T))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
type_info_base :: runtime.type_info_base
|
||||||
if info == nil { return nil }
|
type_info_core :: runtime.type_info_core
|
||||||
|
|
||||||
base := info
|
|
||||||
loop: for {
|
|
||||||
#partial switch i in base.variant {
|
|
||||||
case Type_Info_Named: base = i.base
|
|
||||||
case: break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type_info_core :: proc(info: ^Type_Info) -> ^Type_Info {
|
|
||||||
if info == nil { return nil }
|
|
||||||
|
|
||||||
base := info
|
|
||||||
loop: for {
|
|
||||||
#partial switch i in base.variant {
|
|
||||||
case Type_Info_Named: base = i.base
|
|
||||||
case Type_Info_Enum: base = i.base
|
|
||||||
case: break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
type_info_base_without_enum :: type_info_core
|
type_info_base_without_enum :: type_info_core
|
||||||
|
|
||||||
|
|
||||||
typeid_base :: proc(id: typeid) -> typeid {
|
when !ODIN_DISALLOW_RTTI {
|
||||||
ti := type_info_of(id)
|
typeid_base :: runtime.typeid_base
|
||||||
ti = type_info_base(ti)
|
typeid_core :: runtime.typeid_core
|
||||||
return ti.id
|
typeid_base_without_enum :: typeid_core
|
||||||
}
|
}
|
||||||
typeid_core :: proc(id: typeid) -> typeid {
|
|
||||||
ti := type_info_base_without_enum(type_info_of(id))
|
|
||||||
return ti.id
|
|
||||||
}
|
|
||||||
typeid_base_without_enum :: typeid_core
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
any_base :: proc(v: any) -> any {
|
any_base :: proc(v: any) -> any {
|
||||||
v := v
|
v := v
|
||||||
if v != nil {
|
if v != nil {
|
||||||
@@ -171,6 +146,7 @@ any_base :: proc(v: any) -> any {
|
|||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
any_core :: proc(v: any) -> any {
|
any_core :: proc(v: any) -> any {
|
||||||
v := v
|
v := v
|
||||||
if v != nil {
|
if v != nil {
|
||||||
@@ -179,6 +155,7 @@ any_core :: proc(v: any) -> any {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
typeid_elem :: proc(id: typeid) -> typeid {
|
typeid_elem :: proc(id: typeid) -> typeid {
|
||||||
ti := type_info_of(id)
|
ti := type_info_of(id)
|
||||||
if ti == nil { return nil }
|
if ti == nil { return nil }
|
||||||
@@ -208,6 +185,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
size_of_typeid :: proc(T: typeid) -> int {
|
size_of_typeid :: proc(T: typeid) -> int {
|
||||||
if ti := type_info_of(T); ti != nil {
|
if ti := type_info_of(T); ti != nil {
|
||||||
return ti.size
|
return ti.size
|
||||||
@@ -215,6 +193,7 @@ size_of_typeid :: proc(T: typeid) -> int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
align_of_typeid :: proc(T: typeid) -> int {
|
align_of_typeid :: proc(T: typeid) -> int {
|
||||||
if ti := type_info_of(T); ti != nil {
|
if ti := type_info_of(T); ti != nil {
|
||||||
return ti.align
|
return ti.align
|
||||||
@@ -222,6 +201,7 @@ align_of_typeid :: proc(T: typeid) -> int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_bytes :: proc(v: any) -> []byte {
|
as_bytes :: proc(v: any) -> []byte {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
sz := size_of_typeid(v.id)
|
sz := size_of_typeid(v.id)
|
||||||
@@ -230,10 +210,12 @@ as_bytes :: proc(v: any) -> []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
any_data :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) {
|
any_data :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) {
|
||||||
return v.data, v.id
|
return v.data, v.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_nil :: proc(v: any) -> bool {
|
is_nil :: proc(v: any) -> bool {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return true
|
return true
|
||||||
@@ -250,6 +232,7 @@ is_nil :: proc(v: any) -> bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
length :: proc(val: any) -> int {
|
length :: proc(val: any) -> int {
|
||||||
if val == nil { return 0 }
|
if val == nil { return 0 }
|
||||||
|
|
||||||
@@ -273,7 +256,7 @@ length :: proc(val: any) -> int {
|
|||||||
return (^runtime.Raw_Dynamic_Array)(val.data).len
|
return (^runtime.Raw_Dynamic_Array)(val.data).len
|
||||||
|
|
||||||
case Type_Info_Map:
|
case Type_Info_Map:
|
||||||
return (^runtime.Raw_Map)(val.data).entries.len
|
return runtime.map_len((^runtime.Raw_Map)(val.data)^)
|
||||||
|
|
||||||
case Type_Info_String:
|
case Type_Info_String:
|
||||||
if a.is_cstring {
|
if a.is_cstring {
|
||||||
@@ -285,6 +268,7 @@ length :: proc(val: any) -> int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
capacity :: proc(val: any) -> int {
|
capacity :: proc(val: any) -> int {
|
||||||
if val == nil { return 0 }
|
if val == nil { return 0 }
|
||||||
|
|
||||||
@@ -305,12 +289,13 @@ capacity :: proc(val: any) -> int {
|
|||||||
return (^runtime.Raw_Dynamic_Array)(val.data).cap
|
return (^runtime.Raw_Dynamic_Array)(val.data).cap
|
||||||
|
|
||||||
case Type_Info_Map:
|
case Type_Info_Map:
|
||||||
return (^runtime.Raw_Map)(val.data).entries.cap
|
return runtime.map_cap((^runtime.Raw_Map)(val.data)^)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||||
if val == nil { return nil }
|
if val == nil { return nil }
|
||||||
|
|
||||||
@@ -370,6 +355,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
deref :: proc(val: any) -> any {
|
deref :: proc(val: any) -> any {
|
||||||
if val != nil {
|
if val != nil {
|
||||||
ti := type_info_base(type_info_of(val.id))
|
ti := type_info_base(type_info_of(val.id))
|
||||||
@@ -399,6 +385,7 @@ Struct_Field :: struct {
|
|||||||
is_using: bool,
|
is_using: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -413,6 +400,7 @@ struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -430,6 +418,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
|
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
|
||||||
if a == nil { return nil }
|
if a == nil { return nil }
|
||||||
|
|
||||||
@@ -461,6 +450,7 @@ struct_field_value_by_name :: proc(a: any, field: string, allow_using := false)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_names :: proc(T: typeid) -> []string {
|
struct_field_names :: proc(T: typeid) -> []string {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -469,6 +459,7 @@ struct_field_names :: proc(T: typeid) -> []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -478,6 +469,7 @@ struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -486,6 +478,7 @@ struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -494,6 +487,7 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -510,11 +504,13 @@ struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
|
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
|
||||||
value, _ = struct_tag_lookup(tag, key)
|
value, _ = struct_tag_lookup(tag, key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
|
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
|
||||||
for t := tag; t != ""; /**/ {
|
for t := tag; t != ""; /**/ {
|
||||||
i := 0
|
i := 0
|
||||||
@@ -573,6 +569,7 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
enum_string :: proc(a: any) -> string {
|
enum_string :: proc(a: any) -> string {
|
||||||
if a == nil { return "" }
|
if a == nil { return "" }
|
||||||
ti := runtime.type_info_base(type_info_of(a.id))
|
ti := runtime.type_info_base(type_info_of(a.id))
|
||||||
@@ -591,6 +588,7 @@ enum_string :: proc(a: any) -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Given a enum type and a value name, get the enum value.
|
// Given a enum type and a value name, get the enum value.
|
||||||
|
@(require_results)
|
||||||
enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
|
enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
|
||||||
ti := type_info_base(type_info_of(Enum_Type))
|
ti := type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||||
@@ -607,6 +605,7 @@ enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, o
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
|
enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||||
@@ -623,6 +622,7 @@ enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
enum_field_names :: proc(Enum_Type: typeid) -> []string {
|
enum_field_names :: proc(Enum_Type: typeid) -> []string {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||||
@@ -630,6 +630,7 @@ enum_field_names :: proc(Enum_Type: typeid) -> []string {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
|
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||||
@@ -643,6 +644,7 @@ Enum_Field :: struct {
|
|||||||
value: Type_Info_Enum_Value,
|
value: Type_Info_Enum_Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||||
@@ -653,15 +655,18 @@ enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
union_variant_type_info :: proc(a: any) -> ^Type_Info {
|
union_variant_type_info :: proc(a: any) -> ^Type_Info {
|
||||||
id := union_variant_typeid(a)
|
id := union_variant_typeid(a)
|
||||||
return type_info_of(id)
|
return type_info_of(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
||||||
return len(info.variants) == 1 && is_pointer(info.variants[0])
|
return len(info.variants) == 1 && is_pointer(info.variants[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
union_variant_typeid :: proc(a: any) -> typeid {
|
union_variant_typeid :: proc(a: any) -> typeid {
|
||||||
if a == nil { return nil }
|
if a == nil { return nil }
|
||||||
|
|
||||||
@@ -690,9 +695,10 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|||||||
case: unimplemented()
|
case: unimplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.data != nil && tag != 0 {
|
if info.no_nil {
|
||||||
i := tag if info.no_nil else tag-1
|
return info.variants[tag].id
|
||||||
return info.variants[i].id
|
} else if tag != 0 {
|
||||||
|
return info.variants[tag-1].id
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -700,6 +706,7 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|||||||
panic("expected a union to reflect.union_variant_typeid")
|
panic("expected a union to reflect.union_variant_typeid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||||
if a == nil { return -1 }
|
if a == nil { return -1 }
|
||||||
|
|
||||||
@@ -730,6 +737,7 @@ get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
|||||||
panic("expected a union to reflect.get_union_variant_raw_tag")
|
panic("expected a union to reflect.get_union_variant_raw_tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
get_union_variant :: proc(a: any) -> any {
|
get_union_variant :: proc(a: any) -> any {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -741,6 +749,7 @@ get_union_variant :: proc(a: any) -> any {
|
|||||||
return any{a.data, id}
|
return any{a.data, id}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
get_union_as_ptr_variants :: proc(val: ^$T) -> (res: intrinsics.type_convert_variants_to_pointers(T)) where intrinsics.type_is_union(T) {
|
get_union_as_ptr_variants :: proc(val: ^$T) -> (res: intrinsics.type_convert_variants_to_pointers(T)) where intrinsics.type_is_union(T) {
|
||||||
ptr := rawptr(val)
|
ptr := rawptr(val)
|
||||||
tag := get_union_variant_raw_tag(val^)
|
tag := get_union_variant_raw_tag(val^)
|
||||||
@@ -881,6 +890,7 @@ set_union_value :: proc(dst: any, value: any) -> bool {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -903,6 +913,7 @@ as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
||||||
v: i64
|
v: i64
|
||||||
v, valid = as_i64(a)
|
v, valid = as_i64(a)
|
||||||
@@ -910,6 +921,7 @@ as_int :: proc(a: any) -> (value: int, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
||||||
v: u64
|
v: u64
|
||||||
v, valid = as_u64(a)
|
v, valid = as_u64(a)
|
||||||
@@ -917,6 +929,7 @@ as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1024,6 +1037,7 @@ as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1133,6 +1147,7 @@ as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1239,6 +1254,7 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_string :: proc(a: any) -> (value: string, valid: bool) {
|
as_string :: proc(a: any) -> (value: string, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1258,6 +1274,7 @@ as_string :: proc(a: any) -> (value: string, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
||||||
if a == nil { return nil }
|
if a == nil { return nil }
|
||||||
a := a
|
a := a
|
||||||
@@ -1272,6 +1289,7 @@ relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
||||||
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
||||||
if ptr^ == 0 {
|
if ptr^ == 0 {
|
||||||
@@ -1314,6 +1332,7 @@ relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1341,6 +1360,7 @@ as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1377,9 +1397,11 @@ ne :: not_equal
|
|||||||
|
|
||||||
DEFAULT_EQUAL_MAX_RECURSION_LEVEL :: 32
|
DEFAULT_EQUAL_MAX_RECURSION_LEVEL :: 32
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
not_equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
not_equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
||||||
return !equal(a, b, including_indirect_array_recursion, recursion_level)
|
return !equal(a, b, including_indirect_array_recursion, recursion_level)
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
||||||
if a == nil && b == nil {
|
if a == nil && b == nil {
|
||||||
return true
|
return true
|
||||||
|
|||||||
+33
-3
@@ -3,17 +3,16 @@ package reflect
|
|||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||||
if a == b {
|
if a == b {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == nil && b != nil) ||
|
if a == nil || b == nil {
|
||||||
(a != nil && b == nil) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case a.size != b.size, a.align != b.align:
|
case a.size != b.size, a.align != b.align:
|
||||||
return false
|
return false
|
||||||
@@ -180,6 +179,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch i in type_info_base(info).variant {
|
#partial switch i in type_info_base(info).variant {
|
||||||
@@ -188,6 +188,7 @@ is_signed :: proc(info: ^Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_unsigned :: proc(info: ^Type_Info) -> bool {
|
is_unsigned :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch i in type_info_base(info).variant {
|
#partial switch i in type_info_base(info).variant {
|
||||||
@@ -197,6 +198,7 @@ is_unsigned :: proc(info: ^Type_Info) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_byte :: proc(info: ^Type_Info) -> bool {
|
is_byte :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch i in type_info_base(info).variant {
|
#partial switch i in type_info_base(info).variant {
|
||||||
@@ -206,66 +208,79 @@ is_byte :: proc(info: ^Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_integer :: proc(info: ^Type_Info) -> bool {
|
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Integer)
|
_, ok := type_info_base(info).variant.(Type_Info_Integer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_rune :: proc(info: ^Type_Info) -> bool {
|
is_rune :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Rune)
|
_, ok := type_info_base(info).variant.(Type_Info_Rune)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_float :: proc(info: ^Type_Info) -> bool {
|
is_float :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Float)
|
_, ok := type_info_base(info).variant.(Type_Info_Float)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_complex :: proc(info: ^Type_Info) -> bool {
|
is_complex :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Complex)
|
_, ok := type_info_base(info).variant.(Type_Info_Complex)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_quaternion :: proc(info: ^Type_Info) -> bool {
|
is_quaternion :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Quaternion)
|
_, ok := type_info_base(info).variant.(Type_Info_Quaternion)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_any :: proc(info: ^Type_Info) -> bool {
|
is_any :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Any)
|
_, ok := type_info_base(info).variant.(Type_Info_Any)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_string :: proc(info: ^Type_Info) -> bool {
|
is_string :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_String)
|
_, ok := type_info_base(info).variant.(Type_Info_String)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_cstring :: proc(info: ^Type_Info) -> bool {
|
is_cstring :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
v, ok := type_info_base(info).variant.(Type_Info_String)
|
v, ok := type_info_base(info).variant.(Type_Info_String)
|
||||||
return ok && v.is_cstring
|
return ok && v.is_cstring
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Boolean)
|
_, ok := type_info_base(info).variant.(Type_Info_Boolean)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
is_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
|
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch v in info.variant {
|
#partial switch v in info.variant {
|
||||||
@@ -277,76 +292,91 @@ is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Procedure)
|
_, ok := type_info_base(info).variant.(Type_Info_Procedure)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_array :: proc(info: ^Type_Info) -> bool {
|
is_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Array)
|
_, ok := type_info_base(info).variant.(Type_Info_Array)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_enumerated_array :: proc(info: ^Type_Info) -> bool {
|
is_enumerated_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array)
|
_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array)
|
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Map)
|
_, ok := type_info_base(info).variant.(Type_Info_Map)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_bit_set :: proc(info: ^Type_Info) -> bool {
|
is_bit_set :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
|
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Slice)
|
_, ok := type_info_base(info).variant.(Type_Info_Slice)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Tuple)
|
_, ok := type_info_base(info).variant.(Type_Info_Tuple)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
||||||
return ok && !s.is_raw_union
|
return ok && !s.is_raw_union
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
||||||
return ok && s.is_raw_union
|
return ok && s.is_raw_union
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_union :: proc(info: ^Type_Info) -> bool {
|
is_union :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Union)
|
_, ok := type_info_base(info).variant.(Type_Info_Union)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Enum)
|
_, ok := type_info_base(info).variant.(Type_Info_Enum)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
|
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
|
||||||
|
|||||||
+35
-7
@@ -143,11 +143,9 @@ Type_Info_Enum :: struct {
|
|||||||
values: []Type_Info_Enum_Value,
|
values: []Type_Info_Enum_Value,
|
||||||
}
|
}
|
||||||
Type_Info_Map :: struct {
|
Type_Info_Map :: struct {
|
||||||
key: ^Type_Info,
|
key: ^Type_Info,
|
||||||
value: ^Type_Info,
|
value: ^Type_Info,
|
||||||
generated_struct: ^Type_Info,
|
map_info: ^Map_Info,
|
||||||
key_equal: Equal_Proc,
|
|
||||||
key_hasher: Hasher_Proc,
|
|
||||||
}
|
}
|
||||||
Type_Info_Bit_Set :: struct {
|
Type_Info_Bit_Set :: struct {
|
||||||
elem: ^Type_Info,
|
elem: ^Type_Info,
|
||||||
@@ -303,6 +301,7 @@ Allocator_Mode :: enum byte {
|
|||||||
Resize,
|
Resize,
|
||||||
Query_Features,
|
Query_Features,
|
||||||
Query_Info,
|
Query_Info,
|
||||||
|
Alloc_Non_Zeroed,
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
|
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
|
||||||
@@ -330,6 +329,12 @@ Allocator :: struct {
|
|||||||
data: rawptr,
|
data: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Byte :: 1
|
||||||
|
Kilobyte :: 1024 * Byte
|
||||||
|
Megabyte :: 1024 * Kilobyte
|
||||||
|
Gigabyte :: 1024 * Megabyte
|
||||||
|
Terabyte :: 1024 * Gigabyte
|
||||||
|
|
||||||
// Logging stuff
|
// Logging stuff
|
||||||
|
|
||||||
Logger_Level :: enum uint {
|
Logger_Level :: enum uint {
|
||||||
@@ -393,9 +398,32 @@ Raw_Dynamic_Array :: struct {
|
|||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The raw, type-erased representation of a map.
|
||||||
|
//
|
||||||
|
// 32-bytes on 64-bit
|
||||||
|
// 16-bytes on 32-bit
|
||||||
Raw_Map :: struct {
|
Raw_Map :: struct {
|
||||||
hashes: []Map_Index,
|
// A single allocation spanning all keys, values, and hashes.
|
||||||
entries: Raw_Dynamic_Array,
|
// {
|
||||||
|
// k: Map_Cell(K) * (capacity / ks_per_cell)
|
||||||
|
// v: Map_Cell(V) * (capacity / vs_per_cell)
|
||||||
|
// h: Map_Cell(H) * (capacity / hs_per_cell)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The data is allocated assuming 64-byte alignment, meaning the address is
|
||||||
|
// always a multiple of 64. This means we have 6 bits of zeros in the pointer
|
||||||
|
// to store the capacity. We can store a value as large as 2^6-1 or 63 in
|
||||||
|
// there. This conveniently is the maximum log2 capacity we can have for a map
|
||||||
|
// as Odin uses signed integers to represent capacity.
|
||||||
|
//
|
||||||
|
// Since the hashes are backed by Map_Hash, which is just a 64-bit unsigned
|
||||||
|
// integer, the cell structure for hashes is unnecessary because 64/8 is 8 and
|
||||||
|
// requires no padding, meaning it can be indexed as a regular array of
|
||||||
|
// 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
|
||||||
|
allocator: Allocator, // 16-bytes on 64-bits, 8-bytes on 32-bits
|
||||||
}
|
}
|
||||||
|
|
||||||
Raw_Any :: struct {
|
Raw_Any :: struct {
|
||||||
|
|||||||
@@ -159,20 +159,7 @@ delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #cal
|
|||||||
}
|
}
|
||||||
@builtin
|
@builtin
|
||||||
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
|
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
|
||||||
Entry :: struct {
|
return map_free_dynamic(transmute(Raw_Map)m, map_info(T), loc)
|
||||||
hash: uintptr,
|
|
||||||
next: int,
|
|
||||||
key: K,
|
|
||||||
value: V,
|
|
||||||
}
|
|
||||||
|
|
||||||
raw := transmute(Raw_Map)m
|
|
||||||
err := delete_slice(raw.hashes, raw.entries.allocator, loc)
|
|
||||||
err1 := mem_free_with_size(raw.entries.data, raw.entries.cap*size_of(Entry), raw.entries.allocator, loc)
|
|
||||||
if err == nil {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -244,12 +231,12 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
@(builtin)
|
@(builtin)
|
||||||
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
|
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_expr_error_loc(loc, cap)
|
make_map_expr_error_loc(loc, capacity)
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
m: T
|
m: T
|
||||||
reserve_map(&m, cap)
|
reserve_map(&m, capacity, loc)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
@(builtin)
|
@(builtin)
|
||||||
@@ -285,36 +272,24 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
|||||||
if m == nil {
|
if m == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
raw_map := (^Raw_Map)(m)
|
map_clear_dynamic((^Raw_Map)(m), map_info(T))
|
||||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
|
|
||||||
entries.len = 0
|
|
||||||
for _, i in raw_map.hashes {
|
|
||||||
raw_map.hashes[i] = MAP_SENTINEL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
h := __get_map_header_table(T)
|
__dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc)
|
||||||
__dynamic_map_reserve(m, h, uint(capacity), loc)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shrinks the capacity of a map down to the current length, or the given capacity.
|
Shrinks the capacity of a map down to the current length.
|
||||||
|
|
||||||
If `new_cap` is negative, then `len(m)` is used.
|
|
||||||
|
|
||||||
Returns false if `cap(m) < new_cap`, or the allocator report failure.
|
|
||||||
|
|
||||||
If `len(m) < new_cap`, then `len(m)` will be left unchanged.
|
|
||||||
*/
|
*/
|
||||||
@builtin
|
@builtin
|
||||||
shrink_map :: proc(m: ^$T/map[$K]$V, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) {
|
shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool) {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
new_cap := new_cap if new_cap >= 0 else len(m)
|
err := map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
|
||||||
return __dynamic_map_shrink(__get_map_header(m), new_cap, loc)
|
did_shrink = err == nil
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -325,14 +300,10 @@ shrink_map :: proc(m: ^$T/map[$K]$V, new_cap := -1, loc := #caller_location) ->
|
|||||||
delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: V) {
|
delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: V) {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
key := key
|
key := key
|
||||||
h := __get_map_header(m)
|
old_k, old_v, ok := map_erase_dynamic((^Raw_Map)(m), map_info(T), uintptr(&key))
|
||||||
fr := __map_find(h, &key)
|
if ok {
|
||||||
if fr.entry_index != MAP_SENTINEL {
|
deleted_key = (^K)(old_k)^
|
||||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
deleted_value = (^V)(old_v)^
|
||||||
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
|
|
||||||
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
|
|
||||||
|
|
||||||
__dynamic_map_erase(h, fr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -573,10 +544,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
|||||||
new_size := capacity * size_of(E)
|
new_size := capacity * size_of(E)
|
||||||
allocator := a.allocator
|
allocator := a.allocator
|
||||||
|
|
||||||
new_data, err := allocator.procedure(
|
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
|
||||||
allocator.data, .Resize, new_size, align_of(E),
|
|
||||||
a.data, old_size, loc,
|
|
||||||
)
|
|
||||||
if new_data == nil || err != nil {
|
if new_data == nil || err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -607,10 +575,7 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
|
|||||||
new_size := length * size_of(E)
|
new_size := length * size_of(E)
|
||||||
allocator := a.allocator
|
allocator := a.allocator
|
||||||
|
|
||||||
new_data, err := allocator.procedure(
|
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
|
||||||
allocator.data, .Resize, new_size, align_of(E),
|
|
||||||
a.data, old_size, loc,
|
|
||||||
)
|
|
||||||
if new_data == nil || err != nil {
|
if new_data == nil || err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -650,15 +615,7 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
|||||||
old_size := a.cap * size_of(E)
|
old_size := a.cap * size_of(E)
|
||||||
new_size := new_cap * size_of(E)
|
new_size := new_cap * size_of(E)
|
||||||
|
|
||||||
new_data, err := a.allocator.procedure(
|
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc)
|
||||||
a.allocator.data,
|
|
||||||
.Resize,
|
|
||||||
new_size,
|
|
||||||
align_of(E),
|
|
||||||
a.data,
|
|
||||||
old_size,
|
|
||||||
loc,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -672,10 +629,7 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
|||||||
@builtin
|
@builtin
|
||||||
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
||||||
key, value := key, value
|
key, value := key, value
|
||||||
h := __get_map_header_table(T)
|
return (^V)(__dynamic_map_set_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc))
|
||||||
|
|
||||||
e := __dynamic_map_set(m, h, __get_map_key_hash(&key), &key, &value, loc)
|
|
||||||
return (^V)(uintptr(e) + h.value_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -731,34 +685,6 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@builtin
|
|
||||||
raw_array_data :: proc "contextless" (a: $P/^($T/[$N]$E)) -> [^]E {
|
|
||||||
return ([^]E)(a)
|
|
||||||
}
|
|
||||||
@builtin
|
|
||||||
raw_simd_data :: proc "contextless" (a: $P/^($T/#simd[$N]$E)) -> [^]E {
|
|
||||||
return ([^]E)(a)
|
|
||||||
}
|
|
||||||
@builtin
|
|
||||||
raw_slice_data :: proc "contextless" (s: $S/[]$E) -> [^]E {
|
|
||||||
ptr := (transmute(Raw_Slice)s).data
|
|
||||||
return ([^]E)(ptr)
|
|
||||||
}
|
|
||||||
@builtin
|
|
||||||
raw_dynamic_array_data :: proc "contextless" (s: $S/[dynamic]$E) -> [^]E {
|
|
||||||
ptr := (transmute(Raw_Dynamic_Array)s).data
|
|
||||||
return ([^]E)(ptr)
|
|
||||||
}
|
|
||||||
@builtin
|
|
||||||
raw_string_data :: proc "contextless" (s: $S/string) -> [^]u8 {
|
|
||||||
return (transmute(Raw_String)s).data
|
|
||||||
}
|
|
||||||
|
|
||||||
@builtin
|
|
||||||
raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_string_data, raw_simd_data}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
@(disabled=ODIN_DISABLE_ASSERT)
|
@(disabled=ODIN_DISABLE_ASSERT)
|
||||||
assert :: proc(condition: bool, message := "", loc := #caller_location) {
|
assert :: proc(condition: bool, message := "", loc := #caller_location) {
|
||||||
|
|||||||
@@ -150,14 +150,14 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, auto_cast length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
resize_soa(&array, length, loc)
|
resize_soa(&array, length, loc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, auto_cast length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
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) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
if reserve_soa(&array, capacity, loc) {
|
if reserve_soa(&array, capacity, loc) {
|
||||||
resize_soa(&array, length, loc)
|
resize_soa(&array, length, loc)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
case .Free:
|
case .Free:
|
||||||
return nil, .None
|
return nil, .None
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
|||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
data, err = _windows_default_alloc(size, alignment)
|
data, err = _windows_default_alloc(size, alignment, mode == .Alloc)
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
_windows_default_free(old_memory)
|
_windows_default_free(old_memory)
|
||||||
@@ -25,7 +25,7 @@ when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
|
|
||||||
case .Query_Info:
|
case .Query_Info:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
|
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 4 * Megabyte)
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||||
@@ -167,7 +167,7 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc, .Alloc_Non_Zeroed:
|
||||||
data, err = default_temp_allocator_alloc(s, size, alignment, loc)
|
data, err = default_temp_allocator_alloc(s, size, alignment, loc)
|
||||||
case .Free:
|
case .Free:
|
||||||
err = default_temp_allocator_free(s, old_memory, loc)
|
err = default_temp_allocator_free(s, old_memory, loc)
|
||||||
@@ -181,7 +181,7 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
|
|||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^Allocator_Mode_Set)(old_memory)
|
set := (^Allocator_Mode_Set)(old_memory)
|
||||||
if set != nil {
|
if set != nil {
|
||||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features}
|
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features}
|
||||||
}
|
}
|
||||||
|
|
||||||
case .Query_Info:
|
case .Query_Info:
|
||||||
@@ -197,4 +197,4 @@ default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator
|
|||||||
procedure = default_temp_allocator_proc,
|
procedure = default_temp_allocator_proc,
|
||||||
data = allocator,
|
data = allocator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -145,6 +145,13 @@ mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, a
|
|||||||
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
|
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_alloc_non_zeroed :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||||
|
if size == 0 || allocator.procedure == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, size, alignment, nil, 0, loc)
|
||||||
|
}
|
||||||
|
|
||||||
mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||||
if ptr == nil || allocator.procedure == nil {
|
if ptr == nil || allocator.procedure == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ _os_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) #no_b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc "contextless" (size: int) -> rawptr {
|
heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr {
|
||||||
HEAP_ZERO_MEMORY :: 0x00000008
|
HEAP_ZERO_MEMORY :: 0x00000008
|
||||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uint(size))
|
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY if zero_memory else 0, uint(size))
|
||||||
}
|
}
|
||||||
heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr {
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
@@ -91,7 +91,7 @@ heap_free :: proc "contextless" (ptr: rawptr) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
_windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, Allocator_Error) {
|
_windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, old_ptr: rawptr = nil, zero_memory := true) -> ([]byte, Allocator_Error) {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
_windows_default_free(old_ptr)
|
_windows_default_free(old_ptr)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -105,7 +105,7 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
|
|||||||
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^
|
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
||||||
} else {
|
} else {
|
||||||
allocated_mem = heap_alloc(space+size_of(rawptr))
|
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
|
||||||
}
|
}
|
||||||
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||||
|
|
||||||
@@ -122,8 +122,8 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
|
|||||||
return byte_slice(aligned_mem, size), nil
|
return byte_slice(aligned_mem, size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_windows_default_alloc :: proc "contextless" (size, alignment: int) -> ([]byte, Allocator_Error) {
|
_windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory := true) -> ([]byte, Allocator_Error) {
|
||||||
return _windows_default_alloc_or_resize(size, alignment, nil)
|
return _windows_default_alloc_or_resize(size, alignment, nil, zero_memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,73 @@ package runtime
|
|||||||
|
|
||||||
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
|
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
when !ODIN_DISALLOW_RTTI {
|
||||||
|
print_any_single :: proc(arg: any) {
|
||||||
|
x := arg
|
||||||
|
if loc, ok := x.(Source_Code_Location); ok {
|
||||||
|
print_caller_location(loc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x.id = typeid_base(x.id)
|
||||||
|
switch v in x {
|
||||||
|
case typeid: print_typeid(v)
|
||||||
|
case ^Type_Info: print_type(v)
|
||||||
|
|
||||||
|
case string: print_string(v)
|
||||||
|
case cstring: print_string(string(v))
|
||||||
|
case []byte: print_string(string(v))
|
||||||
|
|
||||||
|
case rune: print_rune(v)
|
||||||
|
|
||||||
|
case u8: print_u64(u64(v))
|
||||||
|
case u16: print_u64(u64(v))
|
||||||
|
case u16le: print_u64(u64(v))
|
||||||
|
case u16be: print_u64(u64(v))
|
||||||
|
case u32: print_u64(u64(v))
|
||||||
|
case u32le: print_u64(u64(v))
|
||||||
|
case u32be: print_u64(u64(v))
|
||||||
|
case u64: print_u64(u64(v))
|
||||||
|
case u64le: print_u64(u64(v))
|
||||||
|
case u64be: print_u64(u64(v))
|
||||||
|
|
||||||
|
case i8: print_i64(i64(v))
|
||||||
|
case i16: print_i64(i64(v))
|
||||||
|
case i16le: print_i64(i64(v))
|
||||||
|
case i16be: print_i64(i64(v))
|
||||||
|
case i32: print_i64(i64(v))
|
||||||
|
case i32le: print_i64(i64(v))
|
||||||
|
case i32be: print_i64(i64(v))
|
||||||
|
case i64: print_i64(i64(v))
|
||||||
|
case i64le: print_i64(i64(v))
|
||||||
|
case i64be: print_i64(i64(v))
|
||||||
|
|
||||||
|
case int: print_int(v)
|
||||||
|
case uint: print_uint(v)
|
||||||
|
case uintptr: print_uintptr(v)
|
||||||
|
|
||||||
|
case:
|
||||||
|
ti := type_info_of(x.id)
|
||||||
|
#partial switch v in ti.variant {
|
||||||
|
case Type_Info_Pointer:
|
||||||
|
print_uintptr((^uintptr)(x.data)^)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print_string("<invalid-value>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println_any :: proc(args: ..any) {
|
||||||
|
loop: for arg, i in args {
|
||||||
|
if i != 0 {
|
||||||
|
print_string(" ")
|
||||||
|
}
|
||||||
|
print_any_single(arg)
|
||||||
|
}
|
||||||
|
print_string("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
||||||
r := c
|
r := c
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ objc_SEL :: ^intrinsics.objc_selector
|
|||||||
foreign Foundation {
|
foreign Foundation {
|
||||||
objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class ---
|
objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class ---
|
||||||
sel_registerName :: proc "c" (name: cstring) -> objc_SEL ---
|
sel_registerName :: proc "c" (name: cstring) -> objc_SEL ---
|
||||||
objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) ---
|
objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) -> objc_Class ---
|
||||||
|
|
||||||
objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) ---
|
objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) ---
|
||||||
objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 ---
|
objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 ---
|
||||||
|
|||||||
+22
-26
@@ -6,8 +6,8 @@ import "core:runtime"
|
|||||||
_ :: intrinsics
|
_ :: intrinsics
|
||||||
_ :: runtime
|
_ :: runtime
|
||||||
|
|
||||||
map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K) {
|
map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K, err: runtime.Allocator_Error) {
|
||||||
keys = make(type_of(keys), len(m), allocator)
|
keys = make(type_of(keys), len(m), allocator) or_return
|
||||||
i := 0
|
i := 0
|
||||||
for key in m {
|
for key in m {
|
||||||
keys[i] = key
|
keys[i] = key
|
||||||
@@ -15,8 +15,8 @@ map_keys :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (keys: []K)
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (values: []V) {
|
map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (values: []V, err: runtime.Allocator_Error) {
|
||||||
values = make(type_of(values), len(m), allocator)
|
values = make(type_of(values), len(m), allocator) or_return
|
||||||
i := 0
|
i := 0
|
||||||
for _, value in m {
|
for _, value in m {
|
||||||
values[i] = value
|
values[i] = value
|
||||||
@@ -37,8 +37,8 @@ Map_Entry_Info :: struct($Key, $Value: typeid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V)) {
|
map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator_Error) {
|
||||||
entries = make(type_of(entries), len(m), allocator)
|
entries = make(type_of(entries), len(m), allocator) or_return
|
||||||
i := 0
|
i := 0
|
||||||
for key, value in m {
|
for key, value in m {
|
||||||
entries[i].key = key
|
entries[i].key = key
|
||||||
@@ -52,28 +52,24 @@ map_entry_infos :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (ent
|
|||||||
m := m
|
m := m
|
||||||
rm := (^runtime.Raw_Map)(&m)
|
rm := (^runtime.Raw_Map)(&m)
|
||||||
|
|
||||||
info := runtime.type_info_base(type_info_of(M)).variant.(runtime.Type_Info_Map)
|
info := type_info_base(type_info_of(M)).variant.(Type_Info_Map)
|
||||||
gs := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct)
|
if info.map_info != nil {
|
||||||
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
|
entries = make(type_of(entries), len(m), allocator) or_return
|
||||||
entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
|
|
||||||
key_offset := entry_type.offsets[2]
|
|
||||||
value_offset := entry_type.offsets[3]
|
|
||||||
entry_size := uintptr(ed.elem_size)
|
|
||||||
|
|
||||||
entries = make(type_of(entries), rm.entries.len)
|
map_cap := uintptr(cap(m))
|
||||||
|
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(rm^, info.map_info)
|
||||||
|
entry_index := 0
|
||||||
|
for bucket_index in 0..<map_cap {
|
||||||
|
if hash := hs[bucket_index]; runtime.map_hash_is_valid(hash) {
|
||||||
|
key := runtime.map_cell_index_dynamic(ks, &info.map_info.ks, bucket_index)
|
||||||
|
value := runtime.map_cell_index_dynamic(vs, &info.map_info.vs, bucket_index)
|
||||||
|
entries[entry_index].hash = hash
|
||||||
|
entries[entry_index].key = (^K)(key)^
|
||||||
|
entries[entry_index].value = (^V)(value)^
|
||||||
|
|
||||||
data := uintptr(rm.entries.data)
|
entry_index += 1
|
||||||
for i in 0..<rm.entries.len {
|
}
|
||||||
header := (^runtime.Map_Entry_Header)(data)
|
}
|
||||||
|
|
||||||
hash := header.hash
|
|
||||||
key := (^K)(data + key_offset)^
|
|
||||||
value := (^V)(data + value_offset)^
|
|
||||||
|
|
||||||
entries[i] = {hash, key, value}
|
|
||||||
|
|
||||||
data += entry_size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-15
@@ -73,24 +73,26 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
|||||||
left, mid, right := left, mid, right
|
left, mid, right := left, mid, right
|
||||||
|
|
||||||
// TODO(bill): Optimization with a buffer for smaller ranges
|
// TODO(bill): Optimization with a buffer for smaller ranges
|
||||||
if left >= right {
|
for left > 0 && right > 0 {
|
||||||
for {
|
if left >= right {
|
||||||
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right)
|
for {
|
||||||
mid = ptr_sub(mid, right)
|
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right * size_of(T))
|
||||||
|
mid = ptr_sub(mid, right)
|
||||||
|
|
||||||
left -= right
|
left -= right
|
||||||
if left < right {
|
if left < right {
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
for {
|
||||||
for {
|
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left * size_of(T))
|
||||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
mid = ptr_add(mid, left)
|
||||||
mid = ptr_add(mid, left)
|
|
||||||
|
|
||||||
right -= left
|
right -= left
|
||||||
if right < left {
|
if right < left {
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,7 @@ swap_between :: proc(a, b: $T/[]$E) {
|
|||||||
reverse :: proc(array: $T/[]$E) {
|
reverse :: proc(array: $T/[]$E) {
|
||||||
n := len(array)/2
|
n := len(array)/2
|
||||||
for i in 0..<n {
|
for i in 0..<n {
|
||||||
a, b := i, len(array)-i-1
|
swap(array, i, len(array)-i-1)
|
||||||
array[a], array[b] = array[b], array[a]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,8 +217,10 @@ rotate_left :: proc(array: $T/[]$E, mid: int) {
|
|||||||
n := len(array)
|
n := len(array)
|
||||||
m := mid %% n
|
m := mid %% n
|
||||||
k := n - m
|
k := n - m
|
||||||
p := raw_data(array)
|
// FIXME: (ap29600) this cast is a temporary fix for the compiler not matching
|
||||||
ptr_rotate(mid, ptr_add(p, mid), k)
|
// [^T] with $P/^$T
|
||||||
|
p := cast(^E)raw_data(array)
|
||||||
|
ptr_rotate(m, ptr_add(p, m), k)
|
||||||
}
|
}
|
||||||
rotate_right :: proc(array: $T/[]$E, k: int) {
|
rotate_right :: proc(array: $T/[]$E, k: int) {
|
||||||
rotate_left(array, -k)
|
rotate_left(array, -k)
|
||||||
@@ -515,4 +516,4 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
|
|||||||
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
|
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
|
||||||
where intrinsics.type_is_enumerated_array(T) {
|
where intrinsics.type_is_enumerated_array(T) {
|
||||||
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
|
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,6 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// merge sort
|
|
||||||
_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
||||||
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
||||||
when KIND == .Ordered {
|
when KIND == .Ordered {
|
||||||
@@ -190,7 +189,9 @@ _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (O
|
|||||||
#panic("unhandled Sort_Kind")
|
#panic("unhandled Sort_Kind")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// insertion sort
|
||||||
|
// TODO(bill): use a different algorithm as insertion sort is O(n^2)
|
||||||
n := len(data)
|
n := len(data)
|
||||||
for i in 1..<n {
|
for i in 1..<n {
|
||||||
for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {
|
for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {
|
||||||
|
|||||||
@@ -9,6 +9,89 @@ Decimal :: struct {
|
|||||||
neg, trunc: bool,
|
neg, trunc: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
|
||||||
|
d^ = {}
|
||||||
|
|
||||||
|
if len(s) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
switch s[i] {
|
||||||
|
case '+': i += 1
|
||||||
|
case '-': i += 1; d.neg = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// digits
|
||||||
|
saw_dot := false
|
||||||
|
saw_digits := false
|
||||||
|
for ; i < len(s); i += 1 {
|
||||||
|
switch {
|
||||||
|
case s[i] == '_':
|
||||||
|
// ignore underscores
|
||||||
|
continue
|
||||||
|
case s[i] == '.':
|
||||||
|
if saw_dot {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
saw_dot = true
|
||||||
|
d.decimal_point = d.count
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '0' <= s[i] && s[i] <= '9':
|
||||||
|
saw_digits = true
|
||||||
|
if s[i] == '0' && d.count == 0 {
|
||||||
|
d.decimal_point -= 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.count < len(d.digits) {
|
||||||
|
d.digits[d.count] = s[i]
|
||||||
|
d.count += 1
|
||||||
|
} else if s[i] != '0' {
|
||||||
|
d.trunc = true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !saw_digits {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !saw_dot {
|
||||||
|
d.decimal_point = d.count
|
||||||
|
}
|
||||||
|
|
||||||
|
lower :: #force_inline proc "contextless" (ch: byte) -> byte { return ('a' - 'A') | ch }
|
||||||
|
|
||||||
|
if i < len(s) && lower(s[i]) == 'e' {
|
||||||
|
i += 1
|
||||||
|
if i >= len(s) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exp_sign := 1
|
||||||
|
switch s[i] {
|
||||||
|
case '+': i += 1
|
||||||
|
case '-': i += 1; exp_sign = -1
|
||||||
|
}
|
||||||
|
if i >= len(s) || s[i] < '0' || s[i] > '9' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := 0
|
||||||
|
for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i += 1 {
|
||||||
|
if s[i] == '_' {
|
||||||
|
// ignore underscores
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if e < 1e4 {
|
||||||
|
e = e*10 + int(s[i]) - '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.decimal_point += e * exp_sign
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == len(s)
|
||||||
|
}
|
||||||
|
|
||||||
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||||
digit_zero :: proc(buf: []byte) -> int {
|
digit_zero :: proc(buf: []byte) -> int {
|
||||||
for _, i in buf {
|
for _, i in buf {
|
||||||
@@ -131,25 +214,128 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
trim(a)
|
trim(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
import "core:runtime"
|
||||||
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
|
println :: proc(args: ..any) {
|
||||||
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
|
for arg, i in args {
|
||||||
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310
|
if i != 0 {
|
||||||
capacity := int(f64(k)*log10_2 + 1)
|
runtime.print_string(" ")
|
||||||
|
}
|
||||||
|
switch v in arg {
|
||||||
|
case string: runtime.print_string(v)
|
||||||
|
case rune: runtime.print_rune(v)
|
||||||
|
case int: runtime.print_int(v)
|
||||||
|
case uint: runtime.print_uint(v)
|
||||||
|
case u8: runtime.print_u64(u64(v))
|
||||||
|
case u16: runtime.print_u64(u64(v))
|
||||||
|
case u32: runtime.print_u64(u64(v))
|
||||||
|
case u64: runtime.print_u64(v)
|
||||||
|
case i8: runtime.print_i64(i64(v))
|
||||||
|
case i16: runtime.print_i64(i64(v))
|
||||||
|
case i32: runtime.print_i64(i64(v))
|
||||||
|
case i64: runtime.print_i64(v)
|
||||||
|
case uintptr: runtime.print_uintptr(v)
|
||||||
|
case bool: runtime.print_string("true" if v else "false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtime.print_string("\n")
|
||||||
|
}
|
||||||
|
|
||||||
r := a.count // read index
|
@(private="file")
|
||||||
w := a.count+capacity // write index
|
_shift_left_offsets := [?]struct{delta: int, cutoff: string}{
|
||||||
|
{ 0, ""},
|
||||||
|
{ 1, "5"},
|
||||||
|
{ 1, "25"},
|
||||||
|
{ 1, "125"},
|
||||||
|
{ 2, "625"},
|
||||||
|
{ 2, "3125"},
|
||||||
|
{ 2, "15625"},
|
||||||
|
{ 3, "78125"},
|
||||||
|
{ 3, "390625"},
|
||||||
|
{ 3, "1953125"},
|
||||||
|
{ 4, "9765625"},
|
||||||
|
{ 4, "48828125"},
|
||||||
|
{ 4, "244140625"},
|
||||||
|
{ 4, "1220703125"},
|
||||||
|
{ 5, "6103515625"},
|
||||||
|
{ 5, "30517578125"},
|
||||||
|
{ 5, "152587890625"},
|
||||||
|
{ 6, "762939453125"},
|
||||||
|
{ 6, "3814697265625"},
|
||||||
|
{ 6, "19073486328125"},
|
||||||
|
{ 7, "95367431640625"},
|
||||||
|
{ 7, "476837158203125"},
|
||||||
|
{ 7, "2384185791015625"},
|
||||||
|
{ 7, "11920928955078125"},
|
||||||
|
{ 8, "59604644775390625"},
|
||||||
|
{ 8, "298023223876953125"},
|
||||||
|
{ 8, "1490116119384765625"},
|
||||||
|
{ 9, "7450580596923828125"},
|
||||||
|
{ 9, "37252902984619140625"},
|
||||||
|
{ 9, "186264514923095703125"},
|
||||||
|
{10, "931322574615478515625"},
|
||||||
|
{10, "4656612873077392578125"},
|
||||||
|
{10, "23283064365386962890625"},
|
||||||
|
{10, "116415321826934814453125"},
|
||||||
|
{11, "582076609134674072265625"},
|
||||||
|
{11, "2910383045673370361328125"},
|
||||||
|
{11, "14551915228366851806640625"},
|
||||||
|
{12, "72759576141834259033203125"},
|
||||||
|
{12, "363797880709171295166015625"},
|
||||||
|
{12, "1818989403545856475830078125"},
|
||||||
|
{13, "9094947017729282379150390625"},
|
||||||
|
{13, "45474735088646411895751953125"},
|
||||||
|
{13, "227373675443232059478759765625"},
|
||||||
|
{13, "1136868377216160297393798828125"},
|
||||||
|
{14, "5684341886080801486968994140625"},
|
||||||
|
{14, "28421709430404007434844970703125"},
|
||||||
|
{14, "142108547152020037174224853515625"},
|
||||||
|
{15, "710542735760100185871124267578125"},
|
||||||
|
{15, "3552713678800500929355621337890625"},
|
||||||
|
{15, "17763568394002504646778106689453125"},
|
||||||
|
{16, "88817841970012523233890533447265625"},
|
||||||
|
{16, "444089209850062616169452667236328125"},
|
||||||
|
{16, "2220446049250313080847263336181640625"},
|
||||||
|
{16, "11102230246251565404236316680908203125"},
|
||||||
|
{17, "55511151231257827021181583404541015625"},
|
||||||
|
{17, "277555756156289135105907917022705078125"},
|
||||||
|
{17, "1387778780781445675529539585113525390625"},
|
||||||
|
{18, "6938893903907228377647697925567626953125"},
|
||||||
|
{18, "34694469519536141888238489627838134765625"},
|
||||||
|
{18, "173472347597680709441192448139190673828125"},
|
||||||
|
{19, "867361737988403547205962240695953369140625"},
|
||||||
|
}
|
||||||
|
|
||||||
d := len(a.digits)
|
shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
|
||||||
|
prefix_less :: #force_inline proc "contextless" (b: []byte, s: string) -> bool #no_bounds_check {
|
||||||
|
for i in 0..<len(s) {
|
||||||
|
if i >= len(b) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if b[i] != s[i] {
|
||||||
|
return b[i] < s[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(k < 61)
|
||||||
|
|
||||||
|
delta := _shift_left_offsets[k].delta
|
||||||
|
if prefix_less(a.digits[:a.count], _shift_left_offsets[k].cutoff) {
|
||||||
|
delta -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
read_index := a.count
|
||||||
|
write_index := a.count+delta
|
||||||
|
|
||||||
n: uint
|
n: uint
|
||||||
for r -= 1; r >= 0; r -= 1 {
|
for read_index -= 1; read_index >= 0; read_index -= 1 {
|
||||||
n += (uint(a.digits[r]) - '0') << k
|
n += (uint(a.digits[read_index]) - '0') << k
|
||||||
quo := n/10
|
quo := n/10
|
||||||
rem := n - 10*quo
|
rem := n - 10*quo
|
||||||
w -= 1
|
write_index -= 1
|
||||||
if w < d {
|
if write_index < len(a.digits) {
|
||||||
a.digits[w] = byte('0' + rem)
|
a.digits[write_index] = byte('0' + rem)
|
||||||
} else if rem != 0 {
|
} else if rem != 0 {
|
||||||
a.trunc = true
|
a.trunc = true
|
||||||
}
|
}
|
||||||
@@ -159,21 +345,18 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
|||||||
for n > 0 {
|
for n > 0 {
|
||||||
quo := n/10
|
quo := n/10
|
||||||
rem := n - 10*quo
|
rem := n - 10*quo
|
||||||
w -= 1
|
write_index -= 1
|
||||||
if w < d {
|
if write_index < len(a.digits) {
|
||||||
a.digits[w] = byte('0' + rem)
|
a.digits[write_index] = byte('0' + rem)
|
||||||
} else if rem != 0 {
|
} else if rem != 0 {
|
||||||
a.trunc = true
|
a.trunc = true
|
||||||
}
|
}
|
||||||
n = quo
|
n = quo
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Remove unused buffer size
|
a.decimal_point += delta
|
||||||
assert(w >= 0)
|
|
||||||
capacity -= w
|
|
||||||
|
|
||||||
a.count = min(a.count+capacity, d)
|
a.count = clamp(a.count, 0, len(a.digits))
|
||||||
a.decimal_point += capacity
|
|
||||||
trim(a)
|
trim(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -284,3 +284,89 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
|
||||||
|
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) {
|
||||||
|
bits = mant & (u64(1)<<info.mantbits - 1)
|
||||||
|
bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
|
||||||
|
if d.neg {
|
||||||
|
bits |= 1<< info.mantbits << info.expbits
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set_overflow :: proc "contextless" (mant: ^u64, exp: ^int, info: ^Float_Info) -> bool {
|
||||||
|
mant^ = 0
|
||||||
|
exp^ = 1<<info.expbits - 1 + info.bias
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
mant: u64
|
||||||
|
exp: int
|
||||||
|
if d.count == 0 {
|
||||||
|
mant = 0
|
||||||
|
exp = info.bias
|
||||||
|
b = end(d, mant, exp, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.decimal_point > 310 {
|
||||||
|
set_overflow(&mant, &exp, info)
|
||||||
|
b = end(d, mant, exp, info)
|
||||||
|
return
|
||||||
|
} else if d.decimal_point < -330 {
|
||||||
|
mant = 0
|
||||||
|
exp = info.bias
|
||||||
|
b = end(d, mant, exp, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@static power_table := [?]int{1, 3, 6, 9, 13, 16, 19, 23, 26}
|
||||||
|
|
||||||
|
exp = 0
|
||||||
|
for d.decimal_point > 0 {
|
||||||
|
n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point]
|
||||||
|
decimal.shift(d, -n)
|
||||||
|
exp += n
|
||||||
|
}
|
||||||
|
for d.decimal_point < 0 || d.decimal_point == 0 && d.digits[0] < '5' {
|
||||||
|
n := 27 if -d.decimal_point >= len(power_table) else power_table[-d.decimal_point]
|
||||||
|
decimal.shift(d, n)
|
||||||
|
exp -= n
|
||||||
|
}
|
||||||
|
|
||||||
|
// go from [0.5, 1) to [1, 2)
|
||||||
|
exp -= 1
|
||||||
|
|
||||||
|
if exp < info.bias + 1 {
|
||||||
|
n := info.bias + 1 - exp
|
||||||
|
decimal.shift(d, n)
|
||||||
|
exp += n
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp-info.bias) >= (1<<info.expbits - 1) {
|
||||||
|
set_overflow(&mant, &exp, info)
|
||||||
|
b = end(d, mant, exp, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decimal.shift(d, int(1 + info.mantbits))
|
||||||
|
mant = decimal.rounded_integer(d)
|
||||||
|
|
||||||
|
if mant == 2<<info.mantbits {
|
||||||
|
mant >>= 1
|
||||||
|
exp += 1
|
||||||
|
if (exp-info.bias) >= (1<<info.expbits - 1) {
|
||||||
|
set_overflow(&mant, &exp, info)
|
||||||
|
b = end(d, mant, exp, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mant & (1<<info.mantbits) == 0 {
|
||||||
|
exp = info.bias
|
||||||
|
}
|
||||||
|
|
||||||
|
b = end(d, mant, exp, info)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package strconv
|
|||||||
Int_Flag :: enum {
|
Int_Flag :: enum {
|
||||||
Prefix,
|
Prefix,
|
||||||
Plus,
|
Plus,
|
||||||
Space,
|
|
||||||
}
|
}
|
||||||
Int_Flags :: bit_set[Int_Flag]
|
Int_Flags :: bit_set[Int_Flag]
|
||||||
|
|
||||||
@@ -73,8 +72,6 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i
|
|||||||
i-=1; a[i] = '-'
|
i-=1; a[i] = '-'
|
||||||
case .Plus in flags:
|
case .Plus in flags:
|
||||||
i-=1; a[i] = '+'
|
i-=1; a[i] = '+'
|
||||||
case .Space in flags:
|
|
||||||
i-=1; a[i] = ' '
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out := a[i:]
|
out := a[i:]
|
||||||
@@ -157,8 +154,6 @@ append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_si
|
|||||||
i-=1; a[i] = '-'
|
i-=1; a[i] = '-'
|
||||||
case .Plus in flags:
|
case .Plus in flags:
|
||||||
i-=1; a[i] = '+'
|
i-=1; a[i] = '+'
|
||||||
case .Space in flags:
|
|
||||||
i-=1; a[i] = ' '
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out := a[i:]
|
out := a[i:]
|
||||||
|
|||||||
+265
-105
@@ -1,6 +1,7 @@
|
|||||||
package strconv
|
package strconv
|
||||||
|
|
||||||
import "core:unicode/utf8"
|
import "core:unicode/utf8"
|
||||||
|
import "decimal"
|
||||||
|
|
||||||
parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) {
|
parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) {
|
||||||
switch s {
|
switch s {
|
||||||
@@ -532,6 +533,8 @@ parse_u128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u128, o
|
|||||||
parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
|
parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
|
||||||
|
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
lower :: #force_inline proc "contextless" (ch: byte) -> byte { return ('a' - 'A') | ch }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -566,126 +569,283 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
|
|||||||
// assert(n == 12.34 && ok);
|
// assert(n == 12.34 && ok);
|
||||||
// ```
|
// ```
|
||||||
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||||
s := str
|
common_prefix_len_ignore_case :: proc "contextless" (s, prefix: string) -> int {
|
||||||
defer if n != nil { n^ = len(str) - len(s) }
|
n := len(prefix)
|
||||||
if s == "" {
|
if n > len(s) {
|
||||||
|
n = len(s)
|
||||||
|
}
|
||||||
|
for i in 0..<n {
|
||||||
|
c := s[i]
|
||||||
|
if 'A' <= c && c <= 'Z' {
|
||||||
|
c += 'a' - 'A'
|
||||||
|
}
|
||||||
|
if c != prefix[i] {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
check_special :: proc "contextless" (s: string) -> (f: f64, n: int, ok: bool) {
|
||||||
|
s := s
|
||||||
|
if len(s) > 0 {
|
||||||
|
sign := 1
|
||||||
|
nsign := 0
|
||||||
|
switch s[0] {
|
||||||
|
case '+', '-':
|
||||||
|
if s[0] == '-' {
|
||||||
|
sign = -1
|
||||||
|
}
|
||||||
|
nsign = 1
|
||||||
|
s = s[1:]
|
||||||
|
fallthrough
|
||||||
|
case 'i', 'I':
|
||||||
|
n := common_prefix_len_ignore_case(s, "infinity")
|
||||||
|
if 3 < n && n < 8 { // "inf" or "infinity"
|
||||||
|
n = 3
|
||||||
|
}
|
||||||
|
if n == 3 || n == 8 {
|
||||||
|
f = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
|
||||||
|
n = nsign + 3
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case 'n', 'N':
|
||||||
|
if common_prefix_len_ignore_case(s, "nan") == 3 {
|
||||||
|
f = 0h7ff80000_00000001
|
||||||
|
n = nsign + 3
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parse_components :: proc "contextless" (s: string) -> (mantissa: u64, exp: int, neg, trunc, hex: bool, i: int, ok: bool) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch s[i] {
|
||||||
|
case '+': i += 1
|
||||||
|
case '-': i += 1; neg = true
|
||||||
|
}
|
||||||
|
|
||||||
|
base := u64(10)
|
||||||
|
MAX_MANT_DIGITS := 19
|
||||||
|
exp_char := byte('e')
|
||||||
|
// support stupid 0x1.ABp100 hex floats even if Odin doesn't
|
||||||
|
if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' {
|
||||||
|
base = 16
|
||||||
|
MAX_MANT_DIGITS = 16
|
||||||
|
i += 2
|
||||||
|
exp_char = 'p'
|
||||||
|
hex = true
|
||||||
|
}
|
||||||
|
|
||||||
|
underscores := false
|
||||||
|
saw_dot, saw_digits := false, false
|
||||||
|
nd := 0
|
||||||
|
nd_mant := 0
|
||||||
|
decimal_point := 0
|
||||||
|
loop: for ; i < len(s); i += 1 {
|
||||||
|
switch c := s[i]; true {
|
||||||
|
case c == '_':
|
||||||
|
underscores = true
|
||||||
|
continue loop
|
||||||
|
case c == '.':
|
||||||
|
if saw_dot {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
saw_dot = true
|
||||||
|
decimal_point = nd
|
||||||
|
continue loop
|
||||||
|
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
saw_digits = true
|
||||||
|
if c == '0' && nd == 0 {
|
||||||
|
decimal_point -= 1
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
nd += 1
|
||||||
|
if nd_mant < MAX_MANT_DIGITS {
|
||||||
|
mantissa *= base
|
||||||
|
mantissa += u64(c - '0')
|
||||||
|
nd_mant += 1
|
||||||
|
} else if c != '0' {
|
||||||
|
trunc = true
|
||||||
|
}
|
||||||
|
continue loop
|
||||||
|
case base == 16 && 'a' <= lower(c) && lower(c) <= 'f':
|
||||||
|
saw_digits = true
|
||||||
|
nd += 1
|
||||||
|
if nd_mant < MAX_MANT_DIGITS {
|
||||||
|
MAX_MANT_DIGITS *= 16
|
||||||
|
MAX_MANT_DIGITS += int(lower(c) - 'a' + 10)
|
||||||
|
nd_mant += 1
|
||||||
|
} else {
|
||||||
|
trunc = true
|
||||||
|
}
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
|
||||||
|
if !saw_digits {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !saw_dot {
|
||||||
|
decimal_point = nd
|
||||||
|
}
|
||||||
|
if base == 16 {
|
||||||
|
decimal_point *= 4
|
||||||
|
nd_mant *= 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < len(s) && lower(s[i]) == exp_char {
|
||||||
|
i += 1
|
||||||
|
if i >= len(s) { return }
|
||||||
|
exp_sign := 1
|
||||||
|
switch s[i] {
|
||||||
|
case '+': i += 1
|
||||||
|
case '-': i += 1; exp_sign = -1
|
||||||
|
}
|
||||||
|
if i >= len(s) || s[i] < '0' || s[i] > '9' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := 0
|
||||||
|
for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i += 1 {
|
||||||
|
if s[i] == '_' {
|
||||||
|
underscores = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if e < 1e5 {
|
||||||
|
e = e*10 + int(s[i]) - '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decimal_point += e * exp_sign
|
||||||
|
} else if base == 16 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if mantissa != 0 {
|
||||||
|
exp = decimal_point - nd_mant
|
||||||
|
}
|
||||||
|
// TODO(bill): check underscore correctness
|
||||||
|
ok = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
parse_hex :: proc(s: string, mantissa: u64, exp: int, neg, trunc: bool) -> (f64, bool) {
|
||||||
|
info := &_f64_info
|
||||||
|
|
||||||
sign: f64 = 1
|
mantissa, exp := mantissa, exp
|
||||||
switch s[i] {
|
|
||||||
case '-': i += 1; sign = -1
|
|
||||||
case '+': i += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
for ; i < len(s); i += 1 {
|
MAX_EXP := 1<<info.expbits + info.bias - 2
|
||||||
r := rune(s[i])
|
MIN_EXP := info.bias + 1
|
||||||
if r == '_' {
|
exp += int(info.mantbits)
|
||||||
continue
|
|
||||||
|
for mantissa != 0 && mantissa >> (info.mantbits+2) == 0 {
|
||||||
|
mantissa <<= 1
|
||||||
|
exp -= 1
|
||||||
|
}
|
||||||
|
if trunc {
|
||||||
|
mantissa |= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
v := _digit_value(r)
|
for mantissa >> (info.mantbits+2) == 0 {
|
||||||
if v >= 10 {
|
mantissa = mantissa>>1 | mantissa&1
|
||||||
if r == '.' || r == 'e' || r == 'E' { // Skip parsing NaN and Inf if it's probably a regular float
|
exp += 1
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(s) >= 3 + i {
|
|
||||||
buf: [4]u8
|
|
||||||
copy(buf[:], s[i:][:3])
|
|
||||||
|
|
||||||
v2 := transmute(u32)buf
|
|
||||||
v2 &= 0xDFDFDFDF // Knock out lower-case bits
|
|
||||||
|
|
||||||
buf = transmute([4]u8)v2
|
|
||||||
|
|
||||||
when ODIN_ENDIAN == .Little {
|
|
||||||
if v2 == 0x464e49 { // "INF"
|
|
||||||
s = s[3+i:]
|
|
||||||
value = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
|
|
||||||
return value, len(s) == 0
|
|
||||||
} else if v2 == 0x4e414e { // "NAN"
|
|
||||||
s = s[3+i:]
|
|
||||||
return 0h7ff80000_00000001, len(s) == 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if v2 == 0x494e4600 { // "\0FNI"
|
|
||||||
s = s[3+i:]
|
|
||||||
value = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
|
|
||||||
return value, len(s) == 0
|
|
||||||
} else if v2 == 0x4e414e00 { // "\0NAN"
|
|
||||||
s = s[3+i:]
|
|
||||||
return 0h7ff80000_00000001, len(s) == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
value *= 10
|
|
||||||
value += f64(v)
|
// denormalize
|
||||||
|
if mantissa > 1 && exp < MIN_EXP-2 {
|
||||||
|
mantissa = mantissa>>1 | mantissa&1
|
||||||
|
exp += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
round := mantissa & 3
|
||||||
|
mantissa >>= 2
|
||||||
|
round |= mantissa & 1 // round to even
|
||||||
|
exp += 2
|
||||||
|
if round == 3 {
|
||||||
|
mantissa += 1
|
||||||
|
if mantissa == 1 << (1 + info.mantbits) {
|
||||||
|
mantissa >>= 1
|
||||||
|
exp += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mantissa>>info.mantbits == 0 {
|
||||||
|
// zero or denormal
|
||||||
|
exp = info.bias
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := true
|
||||||
|
if exp > MAX_EXP {
|
||||||
|
// infinity or invalid
|
||||||
|
mantissa = 1<<info.mantbits
|
||||||
|
exp = MAX_EXP + 1
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
bits := mantissa & (1<<info.mantbits - 1)
|
||||||
|
bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
|
||||||
|
if neg {
|
||||||
|
bits |= 1 << info.mantbits << info.expbits
|
||||||
|
}
|
||||||
|
return transmute(f64)bits, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
if i < len(s) && s[i] == '.' {
|
|
||||||
pow10: f64 = 10
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
for ; i < len(s); i += 1 {
|
nr: int
|
||||||
r := rune(s[i])
|
defer if n != nil { n^ = nr }
|
||||||
if r == '_' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
v := _digit_value(r)
|
if value, nr, ok = check_special(str); ok {
|
||||||
if v >= 10 {
|
return
|
||||||
break
|
}
|
||||||
|
|
||||||
|
mantissa: u64
|
||||||
|
exp: int
|
||||||
|
neg, trunc, hex: bool
|
||||||
|
mantissa, exp, neg, trunc, hex, nr = parse_components(str) or_return
|
||||||
|
|
||||||
|
if hex {
|
||||||
|
return parse_hex(str, mantissa, exp, neg, trunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
trunc_block: if !trunc {
|
||||||
|
@static pow10 := [?]f64{
|
||||||
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||||
|
1e20, 1e21, 1e22,
|
||||||
|
}
|
||||||
|
|
||||||
|
if mantissa>>_f64_info.mantbits != 0 {
|
||||||
|
break trunc_block
|
||||||
|
}
|
||||||
|
f := f64(mantissa)
|
||||||
|
if neg {
|
||||||
|
f = -f
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case exp == 0:
|
||||||
|
return f, true
|
||||||
|
case exp > 0 && exp <= 15+22:
|
||||||
|
if exp > 22 {
|
||||||
|
f *= pow10[exp-22]
|
||||||
|
exp = 22
|
||||||
}
|
}
|
||||||
value += f64(v)/pow10
|
if f > 1e15 || f < 1e-15 {
|
||||||
pow10 *= 10
|
break trunc_block
|
||||||
|
}
|
||||||
|
return f * pow10[exp], true
|
||||||
|
case -22 <= exp && exp < 0:
|
||||||
|
return f / pow10[-exp], true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
d: decimal.Decimal
|
||||||
frac := false
|
decimal.set(&d, str[:nr])
|
||||||
scale: f64 = 1
|
b, overflow := decimal_to_float_bits(&d, &_f64_info)
|
||||||
|
value = transmute(f64)b
|
||||||
if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
|
ok = !overflow
|
||||||
i += 1
|
|
||||||
|
|
||||||
if i < len(s) {
|
|
||||||
switch s[i] {
|
|
||||||
case '-': i += 1; frac = true
|
|
||||||
case '+': i += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
exp: u32 = 0
|
|
||||||
for ; i < len(s); i += 1 {
|
|
||||||
r := rune(s[i])
|
|
||||||
if r == '_' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
d := u32(_digit_value(r))
|
|
||||||
if d >= 10 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
exp = exp * 10 + d
|
|
||||||
}
|
|
||||||
if exp > 308 { exp = 308 }
|
|
||||||
|
|
||||||
for exp >= 50 { scale *= 1e50; exp -= 50 }
|
|
||||||
for exp >= 8 { scale *= 1e8; exp -= 8 }
|
|
||||||
for exp > 0 { scale *= 10; exp -= 1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = s[i:]
|
|
||||||
|
|
||||||
if frac {
|
|
||||||
value = sign * (value/scale)
|
|
||||||
} else {
|
|
||||||
value = sign * (value*scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = len(s) == 0
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,50 @@ write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writes a f64 value into the builder, returns the written amount of characters
|
||||||
|
write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) {
|
||||||
|
buf: [384]byte
|
||||||
|
s := strconv.append_float(buf[:], f, fmt, prec, bit_size)
|
||||||
|
// If the result starts with a `+` then unless we always want signed results,
|
||||||
|
// we skip it unless it's followed by an `I` (because of +Inf).
|
||||||
|
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
return write_string(b, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes a f16 value into the builder, returns the written amount of characters
|
||||||
|
write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) {
|
||||||
|
buf: [384]byte
|
||||||
|
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||||
|
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
return write_string(b, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes a f32 value into the builder, returns the written amount of characters
|
||||||
|
write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) {
|
||||||
|
buf: [384]byte
|
||||||
|
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||||
|
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
return write_string(b, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writes a f64 value into the builder, returns the written amount of characters
|
||||||
|
write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) {
|
||||||
|
buf: [384]byte
|
||||||
|
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||||
|
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
return write_string(b, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters
|
// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters
|
||||||
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
|
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
|
||||||
buf: [32]byte
|
buf: [32]byte
|
||||||
|
|||||||
+95
-30
@@ -1,6 +1,8 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import vg "core:sys/valgrind"
|
||||||
|
_ :: vg
|
||||||
|
|
||||||
// A Wait_Group waits for a collection of threads to finish
|
// A Wait_Group waits for a collection of threads to finish
|
||||||
//
|
//
|
||||||
@@ -11,7 +13,7 @@ Wait_Group :: struct {
|
|||||||
cond: Cond,
|
cond: Cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
|
||||||
if delta == 0 {
|
if delta == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -20,32 +22,32 @@ wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
|||||||
|
|
||||||
atomic_add(&wg.counter, delta)
|
atomic_add(&wg.counter, delta)
|
||||||
if wg.counter < 0 {
|
if wg.counter < 0 {
|
||||||
panic("sync.Wait_Group negative counter")
|
_panic("sync.Wait_Group negative counter")
|
||||||
}
|
}
|
||||||
if wg.counter == 0 {
|
if wg.counter == 0 {
|
||||||
cond_broadcast(&wg.cond)
|
cond_broadcast(&wg.cond)
|
||||||
if wg.counter != 0 {
|
if wg.counter != 0 {
|
||||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_group_done :: proc(wg: ^Wait_Group) {
|
wait_group_done :: proc "contextless" (wg: ^Wait_Group) {
|
||||||
wait_group_add(wg, -1)
|
wait_group_add(wg, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_group_wait :: proc(wg: ^Wait_Group) {
|
wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
|
||||||
guard(&wg.mutex)
|
guard(&wg.mutex)
|
||||||
|
|
||||||
if wg.counter != 0 {
|
if wg.counter != 0 {
|
||||||
cond_wait(&wg.cond, &wg.mutex)
|
cond_wait(&wg.cond, &wg.mutex)
|
||||||
if wg.counter != 0 {
|
if wg.counter != 0 {
|
||||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -> bool {
|
wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: time.Duration) -> bool {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if wg.counter != 0 {
|
if wg.counter != 0 {
|
||||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -76,7 +78,7 @@ Example:
|
|||||||
|
|
||||||
barrier := &sync.Barrier{}
|
barrier := &sync.Barrier{}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc "contextless" () {
|
||||||
fmt.println("Start")
|
fmt.println("Start")
|
||||||
|
|
||||||
THREAD_COUNT :: 4
|
THREAD_COUNT :: 4
|
||||||
@@ -107,7 +109,10 @@ Barrier :: struct {
|
|||||||
thread_count: int,
|
thread_count: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier_init :: proc(b: ^Barrier, thread_count: int) {
|
barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_barrier_resize_pre(b, uint(thread_count))
|
||||||
|
}
|
||||||
b.index = 0
|
b.index = 0
|
||||||
b.generation_id = 0
|
b.generation_id = 0
|
||||||
b.thread_count = thread_count
|
b.thread_count = thread_count
|
||||||
@@ -115,7 +120,10 @@ barrier_init :: proc(b: ^Barrier, thread_count: int) {
|
|||||||
|
|
||||||
// Block the current thread until all threads have rendezvoused
|
// Block the current thread until all threads have rendezvoused
|
||||||
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
|
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
|
||||||
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) {
|
barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_barrier_wait_pre(b)
|
||||||
|
}
|
||||||
guard(&b.mutex)
|
guard(&b.mutex)
|
||||||
local_gen := b.generation_id
|
local_gen := b.generation_id
|
||||||
b.index += 1
|
b.index += 1
|
||||||
@@ -141,7 +149,7 @@ Auto_Reset_Event :: struct {
|
|||||||
sema: Sema,
|
sema: Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
|
auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {
|
||||||
old_status := atomic_load_explicit(&e.status, .Relaxed)
|
old_status := atomic_load_explicit(&e.status, .Relaxed)
|
||||||
for {
|
for {
|
||||||
new_status := old_status + 1 if old_status < 1 else 1
|
new_status := old_status + 1 if old_status < 1 else 1
|
||||||
@@ -155,7 +163,7 @@ auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) {
|
auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) {
|
||||||
old_status := atomic_sub_explicit(&e.status, 1, .Acquire)
|
old_status := atomic_sub_explicit(&e.status, 1, .Acquire)
|
||||||
if old_status < 1 {
|
if old_status < 1 {
|
||||||
sema_wait(&e.sema)
|
sema_wait(&e.sema)
|
||||||
@@ -169,18 +177,18 @@ Ticket_Mutex :: struct {
|
|||||||
serving: uint,
|
serving: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) {
|
ticket_mutex_lock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
|
||||||
ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed)
|
ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed)
|
||||||
for ticket != atomic_load_explicit(&m.serving, .Acquire) {
|
for ticket != atomic_load_explicit(&m.serving, .Acquire) {
|
||||||
cpu_relax()
|
cpu_relax()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) {
|
ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
|
||||||
atomic_add_explicit(&m.serving, 1, .Relaxed)
|
atomic_add_explicit(&m.serving, 1, .Relaxed)
|
||||||
}
|
}
|
||||||
@(deferred_in=ticket_mutex_unlock)
|
@(deferred_in=ticket_mutex_unlock)
|
||||||
ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> bool {
|
ticket_mutex_guard :: proc "contextless" (m: ^Ticket_Mutex) -> bool {
|
||||||
ticket_mutex_lock(m)
|
ticket_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -191,25 +199,25 @@ Benaphore :: struct {
|
|||||||
sema: Sema,
|
sema: Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
benaphore_lock :: proc(b: ^Benaphore) {
|
benaphore_lock :: proc "contextless" (b: ^Benaphore) {
|
||||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||||
sema_wait(&b.sema)
|
sema_wait(&b.sema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
benaphore_try_lock :: proc(b: ^Benaphore) -> bool {
|
benaphore_try_lock :: proc "contextless" (b: ^Benaphore) -> bool {
|
||||||
v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire)
|
v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire)
|
||||||
return v == 0
|
return v == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
benaphore_unlock :: proc(b: ^Benaphore) {
|
benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
|
||||||
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
||||||
sema_post(&b.sema)
|
sema_post(&b.sema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(deferred_in=benaphore_unlock)
|
@(deferred_in=benaphore_unlock)
|
||||||
benaphore_guard :: proc(m: ^Benaphore) -> bool {
|
benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
|
||||||
benaphore_lock(m)
|
benaphore_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -221,7 +229,7 @@ Recursive_Benaphore :: struct {
|
|||||||
sema: Sema,
|
sema: Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||||
if tid != b.owner {
|
if tid != b.owner {
|
||||||
@@ -233,7 +241,7 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
|||||||
b.recursion += 1
|
b.recursion += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
if b.owner == tid {
|
if b.owner == tid {
|
||||||
atomic_add_explicit(&b.counter, 1, .Acquire)
|
atomic_add_explicit(&b.counter, 1, .Acquire)
|
||||||
@@ -248,9 +256,9 @@ recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
assert(tid == b.owner)
|
_assert(tid == b.owner, "tid != b.owner")
|
||||||
b.recursion -= 1
|
b.recursion -= 1
|
||||||
recursion := b.recursion
|
recursion := b.recursion
|
||||||
if recursion == 0 {
|
if recursion == 0 {
|
||||||
@@ -265,7 +273,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(deferred_in=recursive_benaphore_unlock)
|
@(deferred_in=recursive_benaphore_unlock)
|
||||||
recursive_benaphore_guard :: proc(m: ^Recursive_Benaphore) -> bool {
|
recursive_benaphore_guard :: proc "contextless" (m: ^Recursive_Benaphore) -> bool {
|
||||||
recursive_benaphore_lock(m)
|
recursive_benaphore_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -282,7 +290,15 @@ Once :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// once_do calls the procedure fn if and only if once_do is being called for the first for this instance of Once.
|
// once_do calls the procedure fn if and only if once_do is being called for the first for this instance of Once.
|
||||||
once_do :: proc(o: ^Once, fn: proc()) {
|
once_do :: proc{
|
||||||
|
once_do_without_data,
|
||||||
|
once_do_without_data_contextless,
|
||||||
|
once_do_with_data,
|
||||||
|
once_do_with_data_contextless,
|
||||||
|
}
|
||||||
|
|
||||||
|
// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once.
|
||||||
|
once_do_without_data :: proc(o: ^Once, fn: proc()) {
|
||||||
@(cold)
|
@(cold)
|
||||||
do_slow :: proc(o: ^Once, fn: proc()) {
|
do_slow :: proc(o: ^Once, fn: proc()) {
|
||||||
guard(&o.m)
|
guard(&o.m)
|
||||||
@@ -292,12 +308,61 @@ once_do :: proc(o: ^Once, fn: proc()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if atomic_load_explicit(&o.done, .Acquire) == false {
|
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||||
do_slow(o, fn)
|
do_slow(o, fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once.
|
||||||
|
once_do_without_data_contextless :: proc(o: ^Once, fn: proc "contextless" ()) {
|
||||||
|
@(cold)
|
||||||
|
do_slow :: proc(o: ^Once, fn: proc "contextless" ()) {
|
||||||
|
guard(&o.m)
|
||||||
|
if !o.done {
|
||||||
|
fn()
|
||||||
|
atomic_store_explicit(&o.done, true, .Release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||||
|
do_slow(o, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// once_do_with_data calls the procedure fn if and only if once_do_with_data is being called for the first for this instance of Once.
|
||||||
|
once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {
|
||||||
|
@(cold)
|
||||||
|
do_slow :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {
|
||||||
|
guard(&o.m)
|
||||||
|
if !o.done {
|
||||||
|
fn(data)
|
||||||
|
atomic_store_explicit(&o.done, true, .Release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||||
|
do_slow(o, fn, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// once_do_with_data_contextless calls the procedure fn if and only if once_do_with_data_contextless is being called for the first for this instance of Once.
|
||||||
|
once_do_with_data_contextless :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {
|
||||||
|
@(cold)
|
||||||
|
do_slow :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {
|
||||||
|
guard(&o.m)
|
||||||
|
if !o.done {
|
||||||
|
fn(data)
|
||||||
|
atomic_store_explicit(&o.done, true, .Release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||||
|
do_slow(o, fn, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// A Parker is an associated token which is initially not present:
|
// A Parker is an associated token which is initially not present:
|
||||||
@@ -314,7 +379,7 @@ Parker :: struct {
|
|||||||
// Blocks the current thread until the token is made available.
|
// Blocks the current thread until the token is made available.
|
||||||
//
|
//
|
||||||
// Assumes this is only called by the thread that owns the Parker.
|
// Assumes this is only called by the thread that owns the Parker.
|
||||||
park :: proc(p: ^Parker) {
|
park :: proc "contextless" (p: ^Parker) {
|
||||||
EMPTY :: 0
|
EMPTY :: 0
|
||||||
NOTIFIED :: 1
|
NOTIFIED :: 1
|
||||||
PARKED :: max(u32)
|
PARKED :: max(u32)
|
||||||
@@ -333,7 +398,7 @@ park :: proc(p: ^Parker) {
|
|||||||
// for a limited duration.
|
// for a limited duration.
|
||||||
//
|
//
|
||||||
// Assumes this is only called by the thread that owns the Parker
|
// Assumes this is only called by the thread that owns the Parker
|
||||||
park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
|
park_with_timeout :: proc "contextless" (p: ^Parker, duration: time.Duration) {
|
||||||
EMPTY :: 0
|
EMPTY :: 0
|
||||||
NOTIFIED :: 1
|
NOTIFIED :: 1
|
||||||
PARKED :: max(u32)
|
PARKED :: max(u32)
|
||||||
@@ -345,7 +410,7 @@ park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Automatically makes thee token available if it was not already.
|
// Automatically makes thee token available if it was not already.
|
||||||
unpark :: proc(p: ^Parker) {
|
unpark :: proc "contextless" (p: ^Parker) {
|
||||||
EMPTY :: 0
|
EMPTY :: 0
|
||||||
NOTIFIED :: 1
|
NOTIFIED :: 1
|
||||||
PARKED :: max(Futex)
|
PARKED :: max(Futex)
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ EINTR :: -4
|
|||||||
EFAULT :: -14
|
EFAULT :: -14
|
||||||
ETIMEDOUT :: -60
|
ETIMEDOUT :: -60
|
||||||
|
|
||||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||||
return _futex_wait_with_timeout(f, expected, 0)
|
return _futex_wait_with_timeout(f, expected, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||||
timeout_ns := u32(duration) * 1000
|
timeout_ns := u32(duration) * 1000
|
||||||
|
|
||||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
||||||
@@ -41,13 +41,13 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return false
|
return false
|
||||||
case:
|
case:
|
||||||
panic("futex_wait failure")
|
_panic("futex_wait failure")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
|
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
|
||||||
if s >= 0 {
|
if s >= 0 {
|
||||||
@@ -59,12 +59,12 @@ _futex_signal :: proc(f: ^Futex) {
|
|||||||
case ENOENT:
|
case ENOENT:
|
||||||
return
|
return
|
||||||
case:
|
case:
|
||||||
panic("futex_wake_single failure")
|
_panic("futex_wake_single failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
|
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
|
||||||
if s >= 0 {
|
if s >= 0 {
|
||||||
@@ -76,7 +76,7 @@ _futex_broadcast :: proc(f: ^Futex) {
|
|||||||
case ENOENT:
|
case ENOENT:
|
||||||
return
|
return
|
||||||
case:
|
case:
|
||||||
panic("futex_wake_all failure")
|
_panic("futex_wake_all failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ foreign libc {
|
|||||||
__error :: proc "c" () -> ^c.int ---
|
__error :: proc "c" () -> ^c.int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||||
timeout := [2]i64{14400, 0} // 4 hours
|
timeout := [2]i64{14400, 0} // 4 hours
|
||||||
for {
|
for {
|
||||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
||||||
@@ -30,12 +30,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("_futex_wait failure")
|
_panic("_futex_wait failure")
|
||||||
}
|
}
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -51,21 +51,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("_futex_wait_with_timeout failure")
|
_panic("_futex_wait_with_timeout failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
|
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
|
||||||
|
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
panic("_futex_signal failure")
|
_panic("_futex_signal failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
|
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
|
||||||
|
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
panic("_futex_broadcast failure")
|
_panic("_futex_broadcast failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -21,20 +21,20 @@ EFAULT :: -14
|
|||||||
EINVAL :: -22
|
EINVAL :: -22
|
||||||
ETIMEDOUT :: -110
|
ETIMEDOUT :: -110
|
||||||
|
|
||||||
get_errno :: proc(r: int) -> int {
|
get_errno :: proc "contextless" (r: int) -> int {
|
||||||
if -4096 < r && r < 0 {
|
if -4096 < r && r < 0 {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
|
internal_futex :: proc "contextless" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
|
||||||
code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
|
code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
|
||||||
return get_errno(code)
|
return get_errno(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||||
err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
|
err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
|
||||||
switch err {
|
switch err {
|
||||||
case ESUCCESS, EINTR, EAGAIN, EINVAL:
|
case ESUCCESS, EINTR, EAGAIN, EINVAL:
|
||||||
@@ -44,12 +44,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
|||||||
case EFAULT:
|
case EFAULT:
|
||||||
fallthrough
|
fallthrough
|
||||||
case:
|
case:
|
||||||
panic("futex_wait failure")
|
_panic("futex_wait failure")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -71,27 +71,27 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
case EFAULT:
|
case EFAULT:
|
||||||
fallthrough
|
fallthrough
|
||||||
case:
|
case:
|
||||||
panic("futex_wait_with_timeout failure")
|
_panic("futex_wait_with_timeout failure")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
|
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
|
||||||
switch err {
|
switch err {
|
||||||
case ESUCCESS, EINVAL, EFAULT:
|
case ESUCCESS, EINVAL, EFAULT:
|
||||||
// okay
|
// okay
|
||||||
case:
|
case:
|
||||||
panic("futex_wake_single failure")
|
_panic("futex_wake_single failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
|
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
|
||||||
switch err {
|
switch err {
|
||||||
case ESUCCESS, EINVAL, EFAULT:
|
case ESUCCESS, EINVAL, EFAULT:
|
||||||
// okay
|
// okay
|
||||||
case:
|
case:
|
||||||
panic("_futex_wake_all failure")
|
_panic("_futex_wake_all failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ foreign libc {
|
|||||||
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
|
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||||
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
|
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
|
||||||
|
|
||||||
if res != -1 {
|
if res != -1 {
|
||||||
@@ -32,10 +32,10 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("futex_wait failure")
|
_panic("futex_wait failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -58,21 +58,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("futex_wait_with_timeout failure")
|
_panic("futex_wait_with_timeout failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
|
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
|
||||||
|
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
panic("futex_wake_single failure")
|
_panic("futex_wake_single failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
|
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
|
||||||
|
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
panic("_futex_wake_all failure")
|
_panic("_futex_wake_all failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,18 @@ package sync
|
|||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||||
return s != 0
|
return s != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
||||||
return s != 0
|
return s != 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||||
if s >= 1 {
|
if s >= 1 {
|
||||||
@@ -25,7 +25,7 @@ _futex_signal :: proc(f: ^Futex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
||||||
if s >= 0 {
|
if s >= 0 {
|
||||||
|
|||||||
@@ -39,22 +39,22 @@ CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_futex_wait :: proc(f: ^Futex, expect: u32) -> bool {
|
_futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> bool {
|
||||||
expect := expect
|
expect := expect
|
||||||
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
|
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool {
|
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> bool {
|
||||||
expect := expect
|
expect := expect
|
||||||
// NOTE(bill): for some bizarre reason, this has be a negative number
|
// NOTE(bill): for some bizarre reason, this has be a negative number
|
||||||
timeout := -i64(duration / 100)
|
timeout := -i64(duration / 100)
|
||||||
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
|
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
WakeByAddressSingle(f)
|
WakeByAddressSingle(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
WakeByAddressAll(f)
|
WakeByAddressAll(f)
|
||||||
}
|
}
|
||||||
+44
-28
@@ -1,5 +1,6 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
|
import "core:runtime"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
current_thread_id :: proc "contextless" () -> int {
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
@@ -15,17 +16,17 @@ Mutex :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mutex_lock locks m
|
// mutex_lock locks m
|
||||||
mutex_lock :: proc(m: ^Mutex) {
|
mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||||
_mutex_lock(m)
|
_mutex_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutex_unlock unlocks m
|
// mutex_unlock unlocks m
|
||||||
mutex_unlock :: proc(m: ^Mutex) {
|
mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||||
_mutex_unlock(m)
|
_mutex_unlock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutex_try_lock tries to lock m, will return true on success, and false on failure
|
// mutex_try_lock tries to lock m, will return true on success, and false on failure
|
||||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
|
||||||
return _mutex_try_lock(m)
|
return _mutex_try_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=mutex_unlock)
|
@(deferred_in=mutex_unlock)
|
||||||
mutex_guard :: proc(m: ^Mutex) -> bool {
|
mutex_guard :: proc "contextless" (m: ^Mutex) -> bool {
|
||||||
mutex_lock(m)
|
mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -52,32 +53,32 @@ RW_Mutex :: struct {
|
|||||||
|
|
||||||
// rw_mutex_lock locks rw for writing (with a single writer)
|
// rw_mutex_lock locks rw for writing (with a single writer)
|
||||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||||
rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
_rw_mutex_lock(rw)
|
_rw_mutex_lock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_unlock unlocks rw for writing (with a single writer)
|
// rw_mutex_unlock unlocks rw for writing (with a single writer)
|
||||||
rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
_rw_mutex_unlock(rw)
|
_rw_mutex_unlock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
// rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
||||||
rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||||
return _rw_mutex_try_lock(rw)
|
return _rw_mutex_try_lock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||||
rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
_rw_mutex_shared_lock(rw)
|
_rw_mutex_shared_lock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
||||||
rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
_rw_mutex_shared_unlock(rw)
|
_rw_mutex_shared_unlock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||||
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||||
return _rw_mutex_try_shared_lock(rw)
|
return _rw_mutex_try_shared_lock(rw)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -87,7 +88,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=rw_mutex_unlock)
|
@(deferred_in=rw_mutex_unlock)
|
||||||
rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool {
|
rw_mutex_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
|
||||||
rw_mutex_lock(m)
|
rw_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=rw_mutex_shared_unlock)
|
@(deferred_in=rw_mutex_shared_unlock)
|
||||||
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> bool {
|
rw_mutex_shared_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
|
||||||
rw_mutex_shared_lock(m)
|
rw_mutex_shared_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -114,15 +115,15 @@ Recursive_Mutex :: struct {
|
|||||||
impl: _Recursive_Mutex,
|
impl: _Recursive_Mutex,
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||||
_recursive_mutex_lock(m)
|
_recursive_mutex_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||||
_recursive_mutex_unlock(m)
|
_recursive_mutex_unlock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||||
return _recursive_mutex_try_lock(m)
|
return _recursive_mutex_try_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=recursive_mutex_unlock)
|
@(deferred_in=recursive_mutex_unlock)
|
||||||
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> bool {
|
recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||||
recursive_mutex_lock(m)
|
recursive_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -147,22 +148,22 @@ Cond :: struct {
|
|||||||
impl: _Cond,
|
impl: _Cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||||
_cond_wait(c, m)
|
_cond_wait(c, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return _cond_wait_with_timeout(c, m, duration)
|
return _cond_wait_with_timeout(c, m, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_signal :: proc(c: ^Cond) {
|
cond_signal :: proc "contextless" (c: ^Cond) {
|
||||||
_cond_signal(c)
|
_cond_signal(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_broadcast :: proc(c: ^Cond) {
|
cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||||
_cond_broadcast(c)
|
_cond_broadcast(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,15 +176,15 @@ Sema :: struct {
|
|||||||
impl: _Sema,
|
impl: _Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
sema_post :: proc(s: ^Sema, count := 1) {
|
sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
||||||
_sema_post(s, count)
|
_sema_post(s, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
sema_wait :: proc(s: ^Sema) {
|
sema_wait :: proc "contextless" (s: ^Sema) {
|
||||||
_sema_wait(s)
|
_sema_wait(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
|
sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
|
||||||
return _sema_wait_with_timeout(s, duration)
|
return _sema_wait_with_timeout(s, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,16 +195,16 @@ sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
|
|||||||
// An Futex must not be copied after first use
|
// An Futex must not be copied after first use
|
||||||
Futex :: distinct u32
|
Futex :: distinct u32
|
||||||
|
|
||||||
futex_wait :: proc(f: ^Futex, expected: u32) {
|
futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {
|
||||||
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_futex_wait(f, expected), "futex_wait failure")
|
_assert(_futex_wait(f, expected), "futex_wait failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if the wait happened within the duration, false if it exceeded the time duration
|
// returns true if the wait happened within the duration, false if it exceeded the time duration
|
||||||
futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||||
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -214,10 +215,25 @@ futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duratio
|
|||||||
return _futex_wait_with_timeout(f, expected, duration)
|
return _futex_wait_with_timeout(f, expected, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
futex_signal :: proc(f: ^Futex) {
|
futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
_futex_signal(f)
|
_futex_signal(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
futex_broadcast :: proc(f: ^Futex) {
|
futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
_futex_broadcast(f)
|
_futex_broadcast(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_assert :: proc "contextless" (cond: bool, msg: string) {
|
||||||
|
if !cond {
|
||||||
|
_panic(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_panic :: proc "contextless" (msg: string) -> ! {
|
||||||
|
runtime.print_string(msg)
|
||||||
|
runtime.print_byte('\n')
|
||||||
|
runtime.trap()
|
||||||
|
}
|
||||||
@@ -18,9 +18,9 @@ Atomic_Mutex :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_mutex_lock locks m
|
// atomic_mutex_lock locks m
|
||||||
atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
atomic_mutex_lock :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||||
@(cold)
|
@(cold)
|
||||||
lock_slow :: proc(m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
|
lock_slow :: proc "contextless" (m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
|
||||||
new_state := curr_state // Make a copy of it
|
new_state := curr_state // Make a copy of it
|
||||||
|
|
||||||
spin_lock: for spin in 0..<i32(100) {
|
spin_lock: for spin in 0..<i32(100) {
|
||||||
@@ -58,9 +58,9 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_mutex_unlock unlocks m
|
// atomic_mutex_unlock unlocks m
|
||||||
atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
|
atomic_mutex_unlock :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||||
@(cold)
|
@(cold)
|
||||||
unlock_slow :: proc(m: ^Atomic_Mutex) {
|
unlock_slow :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||||
futex_signal((^Futex)(&m.state))
|
futex_signal((^Futex)(&m.state))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure
|
// atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure
|
||||||
atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool {
|
atomic_mutex_try_lock :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
|
||||||
_, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume)
|
_, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_mutex_unlock)
|
@(deferred_in=atomic_mutex_unlock)
|
||||||
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> bool {
|
atomic_mutex_guard :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
|
||||||
atomic_mutex_lock(m)
|
atomic_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ Atomic_RW_Mutex :: struct {
|
|||||||
|
|
||||||
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
|
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
|
||||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||||
atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
atomic_rw_mutex_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
|
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||||
atomic_mutex_lock(&rw.mutex)
|
atomic_mutex_lock(&rw.mutex)
|
||||||
|
|
||||||
@@ -128,13 +128,13 @@ atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
|
// atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
|
||||||
atomic_rw_mutex_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
atomic_rw_mutex_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||||
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
|
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
|
||||||
atomic_mutex_unlock(&rw.mutex)
|
atomic_mutex_unlock(&rw.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// atomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
// atomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
||||||
atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||||
if atomic_mutex_try_lock(&rw.mutex) {
|
if atomic_mutex_try_lock(&rw.mutex) {
|
||||||
state := atomic_load(&rw.state)
|
state := atomic_load(&rw.state)
|
||||||
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
|
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
|
||||||
@@ -148,7 +148,7 @@ atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||||
atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
atomic_rw_mutex_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||||
state := atomic_load(&rw.state)
|
state := atomic_load(&rw.state)
|
||||||
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||||
ok: bool
|
ok: bool
|
||||||
@@ -164,7 +164,7 @@ atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
// atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
||||||
atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||||
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader)
|
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||||
|
|
||||||
if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
|
if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
|
||||||
@@ -174,7 +174,7 @@ atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||||
atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
atomic_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||||
state := atomic_load(&rw.state)
|
state := atomic_load(&rw.state)
|
||||||
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||||
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||||
@@ -198,7 +198,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_rw_mutex_unlock)
|
@(deferred_in=atomic_rw_mutex_unlock)
|
||||||
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
atomic_rw_mutex_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
|
||||||
atomic_rw_mutex_lock(m)
|
atomic_rw_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_rw_mutex_shared_unlock)
|
@(deferred_in=atomic_rw_mutex_shared_unlock)
|
||||||
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
atomic_rw_mutex_shared_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
|
||||||
atomic_rw_mutex_shared_lock(m)
|
atomic_rw_mutex_shared_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ Atomic_Recursive_Mutex :: struct {
|
|||||||
mutex: Mutex,
|
mutex: Mutex,
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
|
atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
if tid != m.owner {
|
if tid != m.owner {
|
||||||
mutex_lock(&m.mutex)
|
mutex_lock(&m.mutex)
|
||||||
@@ -238,9 +238,9 @@ atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
|
|||||||
m.recursion += 1
|
m.recursion += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
|
atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
assert(tid == m.owner)
|
_assert(tid == m.owner, "tid != m.owner")
|
||||||
m.recursion -= 1
|
m.recursion -= 1
|
||||||
recursion := m.recursion
|
recursion := m.recursion
|
||||||
if recursion == 0 {
|
if recursion == 0 {
|
||||||
@@ -253,7 +253,7 @@ atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
atomic_recursive_mutex_try_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
if m.owner == tid {
|
if m.owner == tid {
|
||||||
return mutex_try_lock(&m.mutex)
|
return mutex_try_lock(&m.mutex)
|
||||||
@@ -274,7 +274,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_recursive_mutex_unlock)
|
@(deferred_in=atomic_recursive_mutex_unlock)
|
||||||
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
atomic_recursive_mutex_guard :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
|
||||||
atomic_recursive_mutex_lock(m)
|
atomic_recursive_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ Atomic_Cond :: struct {
|
|||||||
state: Futex,
|
state: Futex,
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
atomic_cond_wait :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
||||||
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
||||||
unlock(m)
|
unlock(m)
|
||||||
futex_wait(&c.state, state)
|
futex_wait(&c.state, state)
|
||||||
@@ -297,7 +297,7 @@ atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
|
atomic_cond_wait_with_timeout :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
|
||||||
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
||||||
unlock(m)
|
unlock(m)
|
||||||
ok = futex_wait_with_timeout(&c.state, state, duration)
|
ok = futex_wait_with_timeout(&c.state, state, duration)
|
||||||
@@ -306,12 +306,12 @@ atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
atomic_cond_signal :: proc(c: ^Atomic_Cond) {
|
atomic_cond_signal :: proc "contextless" (c: ^Atomic_Cond) {
|
||||||
atomic_add_explicit(&c.state, 1, .Release)
|
atomic_add_explicit(&c.state, 1, .Release)
|
||||||
futex_signal(&c.state)
|
futex_signal(&c.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_cond_broadcast :: proc(c: ^Atomic_Cond) {
|
atomic_cond_broadcast :: proc "contextless" (c: ^Atomic_Cond) {
|
||||||
atomic_add_explicit(&c.state, 1, .Release)
|
atomic_add_explicit(&c.state, 1, .Release)
|
||||||
futex_broadcast(&c.state)
|
futex_broadcast(&c.state)
|
||||||
}
|
}
|
||||||
@@ -324,7 +324,7 @@ Atomic_Sema :: struct {
|
|||||||
count: Futex,
|
count: Futex,
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
|
atomic_sema_post :: proc "contextless" (s: ^Atomic_Sema, count := 1) {
|
||||||
atomic_add_explicit(&s.count, Futex(count), .Release)
|
atomic_add_explicit(&s.count, Futex(count), .Release)
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
futex_signal(&s.count)
|
futex_signal(&s.count)
|
||||||
@@ -333,7 +333,7 @@ atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_sema_wait :: proc(s: ^Atomic_Sema) {
|
atomic_sema_wait :: proc "contextless" (s: ^Atomic_Sema) {
|
||||||
for {
|
for {
|
||||||
original_count := atomic_load_explicit(&s.count, .Relaxed)
|
original_count := atomic_load_explicit(&s.count, .Relaxed)
|
||||||
for original_count == 0 {
|
for original_count == 0 {
|
||||||
@@ -346,7 +346,7 @@ atomic_sema_wait :: proc(s: ^Atomic_Sema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) -> bool {
|
atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration: time.Duration) -> bool {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,31 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import vg "core:sys/valgrind"
|
||||||
|
_ :: vg
|
||||||
|
|
||||||
_Sema :: struct {
|
_Sema :: struct {
|
||||||
atomic: Atomic_Sema,
|
atomic: Atomic_Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
_sema_post :: proc(s: ^Sema, count := 1) {
|
_sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_sem_post_pre(s)
|
||||||
|
}
|
||||||
atomic_sema_post(&s.impl.atomic, count)
|
atomic_sema_post(&s.impl.atomic, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
_sema_wait :: proc(s: ^Sema) {
|
_sema_wait :: proc "contextless" (s: ^Sema) {
|
||||||
atomic_sema_wait(&s.impl.atomic)
|
atomic_sema_wait(&s.impl.atomic)
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_sem_wait_post(s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
|
_sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
defer vg.helgrind_sem_wait_post(s)
|
||||||
|
}
|
||||||
return atomic_sema_wait_with_timeout(&s.impl.atomic, duration)
|
return atomic_sema_wait_with_timeout(&s.impl.atomic, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +36,12 @@ _Recursive_Mutex :: struct {
|
|||||||
recursion: i32,
|
recursion: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
_recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_mutex_lock_pre(m, false)
|
||||||
|
defer vg.helgrind_mutex_lock_post(m)
|
||||||
|
}
|
||||||
|
|
||||||
tid := Futex(current_thread_id())
|
tid := Futex(current_thread_id())
|
||||||
for {
|
for {
|
||||||
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
||||||
@@ -40,7 +56,12 @@ _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
_recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_mutex_unlock_pre(m)
|
||||||
|
defer vg.helgrind_mutex_unlock_post(m)
|
||||||
|
}
|
||||||
|
|
||||||
m.impl.recursion -= 1
|
m.impl.recursion -= 1
|
||||||
if m.impl.recursion != 0 {
|
if m.impl.recursion != 0 {
|
||||||
return
|
return
|
||||||
@@ -52,7 +73,7 @@ _recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
_recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||||
tid := Futex(current_thread_id())
|
tid := Futex(current_thread_id())
|
||||||
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
||||||
switch prev_owner {
|
switch prev_owner {
|
||||||
@@ -70,15 +91,27 @@ when ODIN_OS != .Windows {
|
|||||||
mutex: Atomic_Mutex,
|
mutex: Atomic_Mutex,
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_lock :: proc(m: ^Mutex) {
|
_mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_mutex_lock_pre(m, false)
|
||||||
|
defer vg.helgrind_mutex_lock_post(m)
|
||||||
|
}
|
||||||
atomic_mutex_lock(&m.impl.mutex)
|
atomic_mutex_lock(&m.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock :: proc(m: ^Mutex) {
|
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_mutex_unlock_pre(m)
|
||||||
|
defer vg.helgrind_mutex_unlock_post(m)
|
||||||
|
}
|
||||||
atomic_mutex_unlock(&m.impl.mutex)
|
atomic_mutex_unlock(&m.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
_mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_mutex_lock_pre(m, true)
|
||||||
|
defer vg.helgrind_mutex_lock_post(m)
|
||||||
|
}
|
||||||
return atomic_mutex_try_lock(&m.impl.mutex)
|
return atomic_mutex_try_lock(&m.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,19 +119,33 @@ when ODIN_OS != .Windows {
|
|||||||
cond: Atomic_Cond,
|
cond: Atomic_Cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
_cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
_ = vg.helgrind_cond_wait_pre(c, m)
|
||||||
|
defer _ = vg.helgrind_cond_wait_post(c, m)
|
||||||
|
}
|
||||||
atomic_cond_wait(&c.impl.cond, &m.impl.mutex)
|
atomic_cond_wait(&c.impl.cond, &m.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
_cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
_ = vg.helgrind_cond_wait_pre(c, m)
|
||||||
|
defer _ = vg.helgrind_cond_wait_post(c, m)
|
||||||
|
}
|
||||||
return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration)
|
return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_signal :: proc(c: ^Cond) {
|
_cond_signal :: proc "contextless" (c: ^Cond) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_cond_signal_pre(c)
|
||||||
|
}
|
||||||
atomic_cond_signal(&c.impl.cond)
|
atomic_cond_signal(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_broadcast :: proc(c: ^Cond) {
|
_cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_cond_broadcast_pre(c)
|
||||||
|
}
|
||||||
atomic_cond_broadcast(&c.impl.cond)
|
atomic_cond_broadcast(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,27 +154,39 @@ when ODIN_OS != .Windows {
|
|||||||
mutex: Atomic_RW_Mutex,
|
mutex: Atomic_RW_Mutex,
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_rwlock_lock_pre(rw, true)
|
||||||
|
}
|
||||||
atomic_rw_mutex_lock(&rw.impl.mutex)
|
atomic_rw_mutex_lock(&rw.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
atomic_rw_mutex_unlock(&rw.impl.mutex)
|
atomic_rw_mutex_unlock(&rw.impl.mutex)
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_rwlock_unlock_post(rw, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
_rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||||
return atomic_rw_mutex_try_lock(&rw.impl.mutex)
|
return atomic_rw_mutex_try_lock(&rw.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_rwlock_lock_pre(rw, false)
|
||||||
|
}
|
||||||
atomic_rw_mutex_shared_lock(&rw.impl.mutex)
|
atomic_rw_mutex_shared_lock(&rw.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
atomic_rw_mutex_shared_unlock(&rw.impl.mutex)
|
atomic_rw_mutex_shared_unlock(&rw.impl.mutex)
|
||||||
|
when ODIN_VALGRIND_SUPPORT {
|
||||||
|
vg.helgrind_rwlock_unlock_post(rw, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||||
return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex)
|
return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,15 +13,15 @@ _Mutex :: struct {
|
|||||||
srwlock: win32.SRWLOCK,
|
srwlock: win32.SRWLOCK,
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_lock :: proc(m: ^Mutex) {
|
_mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||||
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
|
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock :: proc(m: ^Mutex) {
|
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||||
win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
|
win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
_mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
|
||||||
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
|
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,27 +29,27 @@ _RW_Mutex :: struct {
|
|||||||
srwlock: win32.SRWLOCK,
|
srwlock: win32.SRWLOCK,
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
|
win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock)
|
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
_rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||||
return bool(win32.TryAcquireSRWLockExclusive(&rw.impl.srwlock))
|
return bool(win32.TryAcquireSRWLockExclusive(&rw.impl.srwlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
win32.AcquireSRWLockShared(&rw.impl.srwlock)
|
win32.AcquireSRWLockShared(&rw.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
win32.ReleaseSRWLockShared(&rw.impl.srwlock)
|
win32.ReleaseSRWLockShared(&rw.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||||
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
|
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,22 +58,22 @@ _Cond :: struct {
|
|||||||
cond: win32.CONDITION_VARIABLE,
|
cond: win32.CONDITION_VARIABLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
_cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||||
_ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0)
|
_ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
_cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||||
duration := u32(duration / time.Millisecond)
|
duration := u32(duration / time.Millisecond)
|
||||||
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
|
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
|
||||||
return bool(ok)
|
return bool(ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_cond_signal :: proc(c: ^Cond) {
|
_cond_signal :: proc "contextless" (c: ^Cond) {
|
||||||
win32.WakeConditionVariable(&c.impl.cond)
|
win32.WakeConditionVariable(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_broadcast :: proc(c: ^Cond) {
|
_cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||||
win32.WakeAllConditionVariable(&c.impl.cond)
|
win32.WakeAllConditionVariable(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
CPU feature flags can be tested against `cpu_features`, where applicable, e.g.
|
CPU feature flags can be tested against `cpu_features`, where applicable, e.g.
|
||||||
`if .aes in si.aes { ... }`
|
`if .aes in si.aes { ... }`
|
||||||
*/
|
*/
|
||||||
// +ignore
|
//+build ignore
|
||||||
package sysinfo
|
package sysinfo
|
||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|||||||
@@ -464,6 +464,7 @@ macos_release_map: map[string]Darwin_To_Release = {
|
|||||||
"21F2092" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
"21F2092" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||||
"21G72" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
"21G72" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
||||||
"21G83" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
"21G83" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
||||||
|
"21G115" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 0}}},
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
|
|||||||
@@ -128,4 +128,34 @@ foreign advapi32 {
|
|||||||
lpData: LPCVOID,
|
lpData: LPCVOID,
|
||||||
cbData: DWORD,
|
cbData: DWORD,
|
||||||
) -> LSTATUS ---
|
) -> LSTATUS ---
|
||||||
|
|
||||||
|
GetFileSecurityW :: proc(
|
||||||
|
lpFileName: LPCWSTR,
|
||||||
|
RequestedInformation: SECURITY_INFORMATION,
|
||||||
|
pSecurityDescriptor: PSECURITY_DESCRIPTOR,
|
||||||
|
nLength: DWORD,
|
||||||
|
lpnLengthNeeded: LPDWORD,
|
||||||
|
) -> BOOL ---
|
||||||
|
|
||||||
|
DuplicateToken :: proc(
|
||||||
|
ExistingTokenHandle: HANDLE,
|
||||||
|
ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL,
|
||||||
|
DuplicateTokenHandle: PHANDLE,
|
||||||
|
) -> BOOL ---
|
||||||
|
|
||||||
|
MapGenericMask :: proc(
|
||||||
|
AccessMask: PDWORD,
|
||||||
|
GenericMapping: PGENERIC_MAPPING,
|
||||||
|
) ---
|
||||||
|
|
||||||
|
AccessCheck :: proc(
|
||||||
|
pSecurityDescriptor: PSECURITY_DESCRIPTOR,
|
||||||
|
ClientToken: HANDLE,
|
||||||
|
DesiredAccess: DWORD,
|
||||||
|
GenericMapping: PGENERIC_MAPPING,
|
||||||
|
PrivilegeSet: PPRIVILEGE_SET,
|
||||||
|
PrivilegeSetLength: LPDWORD,
|
||||||
|
GrantedAccess: LPDWORD,
|
||||||
|
AccessStatus: LPBOOL,
|
||||||
|
) -> BOOL ---
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// +build windows
|
||||||
|
package sys_windows
|
||||||
|
|
||||||
|
foreign import "system:Comctl32.lib"
|
||||||
|
|
||||||
|
@(default_calling_convention="stdcall")
|
||||||
|
foreign Comctl32 {
|
||||||
|
LoadIconWithScaleDown :: proc(hinst: HINSTANCE, pszName: PCWSTR, cx: c_int, cy: c_int, phico: ^HICON) -> HRESULT ---
|
||||||
|
}
|
||||||
@@ -3,7 +3,45 @@ package sys_windows
|
|||||||
|
|
||||||
foreign import dwmapi "system:Dwmapi.lib"
|
foreign import dwmapi "system:Dwmapi.lib"
|
||||||
|
|
||||||
|
DWMWINDOWATTRIBUTE :: enum {
|
||||||
|
DWMWA_NCRENDERING_ENABLED,
|
||||||
|
DWMWA_NCRENDERING_POLICY,
|
||||||
|
DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||||
|
DWMWA_ALLOW_NCPAINT,
|
||||||
|
DWMWA_CAPTION_BUTTON_BOUNDS,
|
||||||
|
DWMWA_NONCLIENT_RTL_LAYOUT,
|
||||||
|
DWMWA_FORCE_ICONIC_REPRESENTATION,
|
||||||
|
DWMWA_FLIP3D_POLICY,
|
||||||
|
DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||||
|
DWMWA_HAS_ICONIC_BITMAP,
|
||||||
|
DWMWA_DISALLOW_PEEK,
|
||||||
|
DWMWA_EXCLUDED_FROM_PEEK,
|
||||||
|
DWMWA_CLOAK,
|
||||||
|
DWMWA_CLOAKED,
|
||||||
|
DWMWA_FREEZE_REPRESENTATION,
|
||||||
|
DWMWA_PASSIVE_UPDATE_MODE,
|
||||||
|
DWMWA_USE_HOSTBACKDROPBRUSH,
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
|
||||||
|
DWMWA_WINDOW_CORNER_PREFERENCE = 33,
|
||||||
|
DWMWA_BORDER_COLOR,
|
||||||
|
DWMWA_CAPTION_COLOR,
|
||||||
|
DWMWA_TEXT_COLOR,
|
||||||
|
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
|
||||||
|
DWMWA_SYSTEMBACKDROP_TYPE,
|
||||||
|
DWMWA_LAST,
|
||||||
|
}
|
||||||
|
|
||||||
|
DWMNCRENDERINGPOLICY :: enum {
|
||||||
|
DWMNCRP_USEWINDOWSTYLE,
|
||||||
|
DWMNCRP_DISABLED,
|
||||||
|
DWMNCRP_ENABLED,
|
||||||
|
DWMNCRP_LAST,
|
||||||
|
}
|
||||||
|
|
||||||
@(default_calling_convention="stdcall")
|
@(default_calling_convention="stdcall")
|
||||||
foreign dwmapi {
|
foreign dwmapi {
|
||||||
DwmFlush :: proc() -> HRESULT ---
|
DwmFlush :: proc() -> HRESULT ---
|
||||||
|
DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT ---
|
||||||
|
DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT ---
|
||||||
|
DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT ---
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ foreign gdi32 {
|
|||||||
|
|
||||||
SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL ---
|
SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL ---
|
||||||
ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
|
ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
|
||||||
|
DescribePixelFormat :: proc(hdc: HDC, iPixelFormat: c_int, nBytes: UINT, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
|
||||||
SwapBuffers :: proc(HDC) -> BOOL ---
|
SwapBuffers :: proc(HDC) -> BOOL ---
|
||||||
|
|
||||||
SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
|
SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
|
||||||
@@ -77,6 +78,9 @@ foreign gdi32 {
|
|||||||
) -> HFONT ---
|
) -> HFONT ---
|
||||||
TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL ---
|
TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL ---
|
||||||
GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL ---
|
GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL ---
|
||||||
|
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
|
||||||
|
|
||||||
|
CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH ---
|
||||||
}
|
}
|
||||||
|
|
||||||
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
|
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
|
||||||
|
|||||||
@@ -120,6 +120,12 @@ foreign kernel32 {
|
|||||||
bManualReset: BOOL,
|
bManualReset: BOOL,
|
||||||
lpTimerName: LPCWSTR,
|
lpTimerName: LPCWSTR,
|
||||||
) -> HANDLE ---
|
) -> HANDLE ---
|
||||||
|
CreateWaitableTimerExW :: proc(
|
||||||
|
lpTimerAttributes: LPSECURITY_ATTRIBUTES,
|
||||||
|
lpTimerName: LPCWSTR,
|
||||||
|
dwFlags: DWORD,
|
||||||
|
dwDesiredAccess: DWORD,
|
||||||
|
) -> HANDLE ---
|
||||||
SetWaitableTimerEx :: proc(
|
SetWaitableTimerEx :: proc(
|
||||||
hTimer: HANDLE,
|
hTimer: HANDLE,
|
||||||
lpDueTime: ^LARGE_INTEGER,
|
lpDueTime: ^LARGE_INTEGER,
|
||||||
@@ -248,6 +254,17 @@ foreign kernel32 {
|
|||||||
GetModuleHandleW :: proc(lpModuleName: LPCWSTR) -> HMODULE ---
|
GetModuleHandleW :: proc(lpModuleName: LPCWSTR) -> HMODULE ---
|
||||||
GetModuleHandleA :: proc(lpModuleName: LPCSTR) -> HMODULE ---
|
GetModuleHandleA :: proc(lpModuleName: LPCSTR) -> HMODULE ---
|
||||||
GetSystemTimeAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) ---
|
GetSystemTimeAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) ---
|
||||||
|
GetSystemTimePreciseAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) ---
|
||||||
|
FileTimeToSystemTime :: proc(lpFileTime: ^FILETIME, lpSystemTime: ^SYSTEMTIME) -> BOOL ---
|
||||||
|
SystemTimeToTzSpecificLocalTime :: proc(
|
||||||
|
lpTimeZoneInformation: ^TIME_ZONE_INFORMATION,
|
||||||
|
lpUniversalTime: ^SYSTEMTIME,
|
||||||
|
lpLocalTime: ^SYSTEMTIME,
|
||||||
|
) -> BOOL ---
|
||||||
|
SystemTimeToFileTime :: proc(
|
||||||
|
lpSystemTime: ^SYSTEMTIME,
|
||||||
|
lpFileTime: LPFILETIME,
|
||||||
|
) -> BOOL ---
|
||||||
CreateEventW :: proc(
|
CreateEventW :: proc(
|
||||||
lpEventAttributes: LPSECURITY_ATTRIBUTES,
|
lpEventAttributes: LPSECURITY_ATTRIBUTES,
|
||||||
bManualReset: BOOL,
|
bManualReset: BOOL,
|
||||||
@@ -346,6 +363,15 @@ foreign kernel32 {
|
|||||||
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
|
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
|
||||||
FreeConsole :: proc() -> BOOL ---
|
FreeConsole :: proc() -> BOOL ---
|
||||||
GetConsoleWindow :: proc() -> HWND ---
|
GetConsoleWindow :: proc() -> HWND ---
|
||||||
|
|
||||||
|
GetDiskFreeSpaceExW :: proc(
|
||||||
|
lpDirectoryName: LPCWSTR,
|
||||||
|
lpFreeBytesAvailableToCaller: PULARGE_INTEGER,
|
||||||
|
lpTotalNumberOfBytes: PULARGE_INTEGER,
|
||||||
|
lpTotalNumberOfFreeBytes: PULARGE_INTEGER,
|
||||||
|
) -> BOOL ---
|
||||||
|
|
||||||
|
GetLogicalProcessorInformation :: proc(buffer: ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returnedLength: PDWORD) -> BOOL ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -963,4 +989,61 @@ DCB :: struct {
|
|||||||
foreign kernel32 {
|
foreign kernel32 {
|
||||||
GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||||
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LPFIBER_START_ROUTINE :: #type proc "stdcall" (lpFiberParameter: LPVOID)
|
||||||
|
|
||||||
|
@(default_calling_convention = "stdcall")
|
||||||
|
foreign kernel32 {
|
||||||
|
CreateFiber :: proc(dwStackSize: SIZE_T, lpStartAddress: LPFIBER_START_ROUTINE, lpParameter: LPVOID) -> LPVOID ---
|
||||||
|
DeleteFiber :: proc(lpFiber: LPVOID) ---
|
||||||
|
ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID ---
|
||||||
|
SwitchToFiber :: proc(lpFiber: LPVOID) ---
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGICAL_PROCESSOR_RELATIONSHIP :: enum c_int {
|
||||||
|
RelationProcessorCore,
|
||||||
|
RelationNumaNode,
|
||||||
|
RelationCache,
|
||||||
|
RelationProcessorPackage,
|
||||||
|
RelationGroup,
|
||||||
|
RelationProcessorDie,
|
||||||
|
RelationNumaNodeEx,
|
||||||
|
RelationProcessorModule,
|
||||||
|
RelationAll = 0xffff,
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESSOR_CACHE_TYPE :: enum c_int {
|
||||||
|
CacheUnified,
|
||||||
|
CacheInstruction,
|
||||||
|
CacheData,
|
||||||
|
CacheTrace,
|
||||||
|
}
|
||||||
|
|
||||||
|
CACHE_DESCRIPTOR :: struct {
|
||||||
|
Level: BYTE,
|
||||||
|
Associativity: BYTE,
|
||||||
|
LineSize: WORD,
|
||||||
|
Size: DWORD,
|
||||||
|
Type: PROCESSOR_CACHE_TYPE,
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessorCore :: struct {
|
||||||
|
Flags: BYTE,
|
||||||
|
}
|
||||||
|
NumaNode :: struct {
|
||||||
|
NodeNumber: DWORD,
|
||||||
|
}
|
||||||
|
DUMMYUNIONNAME_u :: struct #raw_union {
|
||||||
|
Core: ProcessorCore,
|
||||||
|
Node: NumaNode,
|
||||||
|
Cache: CACHE_DESCRIPTOR,
|
||||||
|
Reserved: [2]ULONGLONG,
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
|
||||||
|
ProcessorMask: ULONG_PTR,
|
||||||
|
Relationship: LOGICAL_PROCESSOR_RELATIONSHIP,
|
||||||
|
DummyUnion: DUMMYUNIONNAME_u,
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,4 +14,45 @@ foreign shell32 {
|
|||||||
lpDirectory: LPCWSTR,
|
lpDirectory: LPCWSTR,
|
||||||
nShowCmd: INT,
|
nShowCmd: INT,
|
||||||
) -> HINSTANCE ---
|
) -> HINSTANCE ---
|
||||||
|
ShellExecuteExW :: proc(pExecInfo: ^SHELLEXECUTEINFOW) -> BOOL ---
|
||||||
|
SHCreateDirectoryExW :: proc(
|
||||||
|
hwnd: HWND,
|
||||||
|
pszPath: LPCWSTR,
|
||||||
|
psa: ^SECURITY_ATTRIBUTES,
|
||||||
|
) -> c_int ---
|
||||||
|
SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
|
||||||
|
SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT ---
|
||||||
|
SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APPBARDATA :: struct {
|
||||||
|
cbSize: DWORD,
|
||||||
|
hWnd: HWND,
|
||||||
|
uCallbackMessage: UINT,
|
||||||
|
uEdge: UINT,
|
||||||
|
rc: RECT,
|
||||||
|
lParam: LPARAM,
|
||||||
|
}
|
||||||
|
PAPPBARDATA :: ^APPBARDATA
|
||||||
|
|
||||||
|
ABM_NEW :: 0x00000000
|
||||||
|
ABM_REMOVE :: 0x00000001
|
||||||
|
ABM_QUERYPOS :: 0x00000002
|
||||||
|
ABM_SETPOS :: 0x00000003
|
||||||
|
ABM_GETSTATE :: 0x00000004
|
||||||
|
ABM_GETTASKBARPOS :: 0x00000005
|
||||||
|
ABM_ACTIVATE :: 0x00000006
|
||||||
|
ABM_GETAUTOHIDEBAR :: 0x00000007
|
||||||
|
ABM_SETAUTOHIDEBAR :: 0x00000008
|
||||||
|
ABM_WINDOWPOSCHANGED :: 0x0000009
|
||||||
|
ABM_SETSTATE :: 0x0000000a
|
||||||
|
ABN_STATECHANGE :: 0x0000000
|
||||||
|
ABN_POSCHANGED :: 0x0000001
|
||||||
|
ABN_FULLSCREENAPP :: 0x0000002
|
||||||
|
ABN_WINDOWARRANGE :: 0x0000003
|
||||||
|
ABS_AUTOHIDE :: 0x0000001
|
||||||
|
ABS_ALWAYSONTOP :: 0x0000002
|
||||||
|
ABE_LEFT :: 0
|
||||||
|
ABE_TOP :: 1
|
||||||
|
ABE_RIGHT :: 2
|
||||||
|
ABE_BOTTOM :: 3
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ foreign shlwapi {
|
|||||||
PathFileExistsW :: proc(pszPath: wstring) -> BOOL ---
|
PathFileExistsW :: proc(pszPath: wstring) -> BOOL ---
|
||||||
PathFindExtensionW :: proc(pszPath: wstring) -> wstring ---
|
PathFindExtensionW :: proc(pszPath: wstring) -> wstring ---
|
||||||
PathFindFileNameW :: proc(pszPath: wstring) -> wstring ---
|
PathFindFileNameW :: proc(pszPath: wstring) -> wstring ---
|
||||||
|
SHAutoComplete :: proc(hwndEdit: HWND, dwFlags: DWORD) -> LWSTDAPI ---
|
||||||
}
|
}
|
||||||
|
|||||||
+393
-4
@@ -20,6 +20,7 @@ DWORD :: c_ulong
|
|||||||
DWORDLONG :: c.ulonglong
|
DWORDLONG :: c.ulonglong
|
||||||
QWORD :: c.ulonglong
|
QWORD :: c.ulonglong
|
||||||
HANDLE :: distinct LPVOID
|
HANDLE :: distinct LPVOID
|
||||||
|
PHANDLE :: ^HANDLE
|
||||||
HINSTANCE :: HANDLE
|
HINSTANCE :: HANDLE
|
||||||
HMODULE :: distinct HINSTANCE
|
HMODULE :: distinct HINSTANCE
|
||||||
HRESULT :: distinct LONG
|
HRESULT :: distinct LONG
|
||||||
@@ -37,12 +38,14 @@ HHOOK :: distinct HANDLE
|
|||||||
HKEY :: distinct HANDLE
|
HKEY :: distinct HANDLE
|
||||||
HDESK :: distinct HANDLE
|
HDESK :: distinct HANDLE
|
||||||
HFONT :: distinct HANDLE
|
HFONT :: distinct HANDLE
|
||||||
|
HRGN :: distinct HANDLE
|
||||||
BOOL :: distinct b32
|
BOOL :: distinct b32
|
||||||
BYTE :: distinct u8
|
BYTE :: distinct u8
|
||||||
BOOLEAN :: distinct b8
|
BOOLEAN :: distinct b8
|
||||||
GROUP :: distinct c_uint
|
GROUP :: distinct c_uint
|
||||||
LARGE_INTEGER :: distinct c_longlong
|
LARGE_INTEGER :: distinct c_longlong
|
||||||
ULARGE_INTEGER :: distinct c_ulonglong
|
ULARGE_INTEGER :: distinct c_ulonglong
|
||||||
|
PULARGE_INTEGER :: ^ULARGE_INTEGER
|
||||||
LONG :: c_long
|
LONG :: c_long
|
||||||
UINT :: c_uint
|
UINT :: c_uint
|
||||||
INT :: c_int
|
INT :: c_int
|
||||||
@@ -133,12 +136,24 @@ LPWSAOVERLAPPED :: distinct rawptr
|
|||||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE :: distinct rawptr
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE :: distinct rawptr
|
||||||
LPCVOID :: rawptr
|
LPCVOID :: rawptr
|
||||||
|
|
||||||
|
PACCESS_TOKEN :: PVOID
|
||||||
|
PSECURITY_DESCRIPTOR :: PVOID
|
||||||
|
PSID :: PVOID
|
||||||
|
PCLAIMS_BLOB :: PVOID
|
||||||
|
|
||||||
PCONDITION_VARIABLE :: ^CONDITION_VARIABLE
|
PCONDITION_VARIABLE :: ^CONDITION_VARIABLE
|
||||||
PLARGE_INTEGER :: ^LARGE_INTEGER
|
PLARGE_INTEGER :: ^LARGE_INTEGER
|
||||||
PSRWLOCK :: ^SRWLOCK
|
PSRWLOCK :: ^SRWLOCK
|
||||||
|
|
||||||
MMRESULT :: UINT
|
MMRESULT :: UINT
|
||||||
|
|
||||||
|
CREATE_WAITABLE_TIMER_MANUAL_RESET :: 0x00000001
|
||||||
|
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION :: 0x00000002
|
||||||
|
|
||||||
|
TIMER_QUERY_STATE :: 0x0001
|
||||||
|
TIMER_MODIFY_STATE :: 0x0002
|
||||||
|
TIMER_ALL_ACCESS :: STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | TIMER_QUERY_STATE | TIMER_MODIFY_STATE
|
||||||
|
|
||||||
SOCKET :: distinct uintptr // TODO
|
SOCKET :: distinct uintptr // TODO
|
||||||
socklen_t :: c_int
|
socklen_t :: c_int
|
||||||
ADDRESS_FAMILY :: USHORT
|
ADDRESS_FAMILY :: USHORT
|
||||||
@@ -175,6 +190,7 @@ FILE_SHARE_DELETE: DWORD : 0x00000004
|
|||||||
FILE_GENERIC_ALL: DWORD : 0x10000000
|
FILE_GENERIC_ALL: DWORD : 0x10000000
|
||||||
FILE_GENERIC_EXECUTE: DWORD : 0x20000000
|
FILE_GENERIC_EXECUTE: DWORD : 0x20000000
|
||||||
FILE_GENERIC_READ: DWORD : 0x80000000
|
FILE_GENERIC_READ: DWORD : 0x80000000
|
||||||
|
FILE_ALL_ACCESS :: STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF
|
||||||
|
|
||||||
FILE_ACTION_ADDED :: 0x00000001
|
FILE_ACTION_ADDED :: 0x00000001
|
||||||
FILE_ACTION_REMOVED :: 0x00000002
|
FILE_ACTION_REMOVED :: 0x00000002
|
||||||
@@ -230,6 +246,20 @@ SECURITY_SQOS_PRESENT: DWORD : 0x00100000
|
|||||||
|
|
||||||
FIONBIO: c_ulong : 0x8004667e
|
FIONBIO: c_ulong : 0x8004667e
|
||||||
|
|
||||||
|
OWNER_SECURITY_INFORMATION :: 0x00000001
|
||||||
|
GROUP_SECURITY_INFORMATION :: 0x00000002
|
||||||
|
DACL_SECURITY_INFORMATION :: 0x00000004
|
||||||
|
SACL_SECURITY_INFORMATION :: 0x00000008
|
||||||
|
LABEL_SECURITY_INFORMATION :: 0x00000010
|
||||||
|
ATTRIBUTE_SECURITY_INFORMATION :: 0x00000020
|
||||||
|
SCOPE_SECURITY_INFORMATION :: 0x00000040
|
||||||
|
PROCESS_TRUST_LABEL_SECURITY_INFORMATION :: 0x00000080
|
||||||
|
ACCESS_FILTER_SECURITY_INFORMATION :: 0x00000100
|
||||||
|
BACKUP_SECURITY_INFORMATION :: 0x00010000
|
||||||
|
PROTECTED_DACL_SECURITY_INFORMATION :: 0x80000000
|
||||||
|
PROTECTED_SACL_SECURITY_INFORMATION :: 0x40000000
|
||||||
|
UNPROTECTED_DACL_SECURITY_INFORMATION :: 0x20000000
|
||||||
|
UNPROTECTED_SACL_SECURITY_INFORMATION :: 0x10000000
|
||||||
|
|
||||||
GET_FILEEX_INFO_LEVELS :: distinct i32
|
GET_FILEEX_INFO_LEVELS :: distinct i32
|
||||||
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0
|
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0
|
||||||
@@ -773,6 +803,61 @@ MSG :: struct {
|
|||||||
|
|
||||||
LPMSG :: ^MSG
|
LPMSG :: ^MSG
|
||||||
|
|
||||||
|
// WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
|
||||||
|
HTERROR :: -2
|
||||||
|
HTTRANSPARENT :: -1
|
||||||
|
HTNOWHERE :: 0
|
||||||
|
HTCLIENT :: 1
|
||||||
|
HTCAPTION :: 2
|
||||||
|
HTSYSMENU :: 3
|
||||||
|
HTGROWBOX :: 4
|
||||||
|
HTSIZE :: HTGROWBOX
|
||||||
|
HTMENU :: 5
|
||||||
|
HTHSCROLL :: 6
|
||||||
|
HTVSCROLL :: 7
|
||||||
|
HTMINBUTTON :: 8
|
||||||
|
HTMAXBUTTON :: 9
|
||||||
|
HTLEFT :: 10
|
||||||
|
HTRIGHT :: 11
|
||||||
|
HTTOP :: 12
|
||||||
|
HTTOPLEFT :: 13
|
||||||
|
HTTOPRIGHT :: 14
|
||||||
|
HTBOTTOM :: 15
|
||||||
|
HTBOTTOMLEFT :: 16
|
||||||
|
HTBOTTOMRIGHT :: 17
|
||||||
|
HTBORDER :: 18
|
||||||
|
HTREDUCE :: HTMINBUTTON
|
||||||
|
HTZOOM :: HTMAXBUTTON
|
||||||
|
HTSIZEFIRST :: HTLEFT
|
||||||
|
HTSIZELAST :: HTBOTTOMRIGHT
|
||||||
|
HTOBJECT :: 19
|
||||||
|
HTCLOSE :: 20
|
||||||
|
HTHELP :: 21
|
||||||
|
|
||||||
|
TEXTMETRICW :: struct {
|
||||||
|
tmHeight: LONG,
|
||||||
|
tmAscent: LONG,
|
||||||
|
tmDescent: LONG,
|
||||||
|
tmInternalLeading: LONG,
|
||||||
|
tmExternalLeading: LONG,
|
||||||
|
tmAveCharWidth: LONG,
|
||||||
|
tmMaxCharWidth: LONG,
|
||||||
|
tmWeight: LONG,
|
||||||
|
tmOverhang: LONG,
|
||||||
|
tmDigitizedAspectX: LONG,
|
||||||
|
tmDigitizedAspectY: LONG,
|
||||||
|
tmFirstChar: WCHAR,
|
||||||
|
tmLastChar: WCHAR,
|
||||||
|
tmDefaultChar: WCHAR,
|
||||||
|
tmBreakChar: WCHAR,
|
||||||
|
tmItalic: BYTE,
|
||||||
|
tmUnderlined: BYTE,
|
||||||
|
tmStruckOut: BYTE,
|
||||||
|
tmPitchAndFamily: BYTE,
|
||||||
|
tmCharSet: BYTE,
|
||||||
|
}
|
||||||
|
LPTEXTMETRICW :: ^TEXTMETRICW
|
||||||
|
|
||||||
PAINTSTRUCT :: struct {
|
PAINTSTRUCT :: struct {
|
||||||
hdc: HDC,
|
hdc: HDC,
|
||||||
fErase: BOOL,
|
fErase: BOOL,
|
||||||
@@ -879,6 +964,48 @@ NM_FONTCHANGED :: NM_OUTOFMEMORY-22
|
|||||||
NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
|
NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
|
||||||
NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
|
NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
|
||||||
|
|
||||||
|
PCZZWSTR :: ^WCHAR
|
||||||
|
|
||||||
|
SHFILEOPSTRUCTW :: struct {
|
||||||
|
hwnd: HWND,
|
||||||
|
wFunc: UINT,
|
||||||
|
pFrom: PCZZWSTR,
|
||||||
|
pTo: PCZZWSTR,
|
||||||
|
fFlags: FILEOP_FLAGS,
|
||||||
|
fAnyOperationsAborted: BOOL,
|
||||||
|
hNameMappings: LPVOID,
|
||||||
|
lpszProgressTitle: PCWSTR, // only used if FOF_SIMPLEPROGRESS
|
||||||
|
}
|
||||||
|
LPSHFILEOPSTRUCTW :: ^SHFILEOPSTRUCTW
|
||||||
|
|
||||||
|
// Shell File Operations
|
||||||
|
FO_MOVE :: 0x0001
|
||||||
|
FO_COPY :: 0x0002
|
||||||
|
FO_DELETE :: 0x0003
|
||||||
|
FO_RENAME :: 0x0004
|
||||||
|
|
||||||
|
// SHFILEOPSTRUCT.fFlags and IFileOperation::SetOperationFlags() flag values
|
||||||
|
FOF_MULTIDESTFILES :: 0x0001
|
||||||
|
FOF_CONFIRMMOUSE :: 0x0002
|
||||||
|
FOF_SILENT :: 0x0004 // don't display progress UI (confirm prompts may be displayed still)
|
||||||
|
FOF_RENAMEONCOLLISION :: 0x0008 // automatically rename the source files to avoid the collisions
|
||||||
|
FOF_NOCONFIRMATION :: 0x0010 // don't display confirmation UI, assume "yes" for cases that can be bypassed, "no" for those that can not
|
||||||
|
FOF_WANTMAPPINGHANDLE :: 0x0020 // Fill in SHFILEOPSTRUCT.hNameMappings
|
||||||
|
// Must be freed using SHFreeNameMappings
|
||||||
|
FOF_ALLOWUNDO :: 0x0040 // enable undo including Recycle behavior for IFileOperation::Delete()
|
||||||
|
FOF_FILESONLY :: 0x0080 // only operate on the files (non folders), both files and folders are assumed without this
|
||||||
|
FOF_SIMPLEPROGRESS :: 0x0100 // means don't show names of files
|
||||||
|
FOF_NOCONFIRMMKDIR :: 0x0200 // don't dispplay confirmatino UI before making any needed directories, assume "Yes" in these cases
|
||||||
|
FOF_NOERRORUI :: 0x0400 // don't put up error UI, other UI may be displayed, progress, confirmations
|
||||||
|
FOF_NOCOPYSECURITYATTRIBS :: 0x0800 // dont copy file security attributes (ACLs)
|
||||||
|
FOF_NORECURSION :: 0x1000 // don't recurse into directories for operations that would recurse
|
||||||
|
FOF_NO_CONNECTED_ELEMENTS :: 0x2000 // don't operate on connected elements ("xxx_files" folders that go with .htm files)
|
||||||
|
FOF_WANTNUKEWARNING :: 0x4000 // during delete operation, warn if object is being permanently destroyed instead of recycling (partially overrides FOF_NOCONFIRMATION)
|
||||||
|
FOF_NORECURSEREPARSE :: 0x8000 // deprecated; the operations engine always does the right thing on FolderLink objects (symlinks, reparse points, folder shortcuts)
|
||||||
|
FOF_NO_UI :: (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR) // don't display any UI at all
|
||||||
|
|
||||||
|
FILEOP_FLAGS :: WORD
|
||||||
|
|
||||||
DEVMODEW :: struct {
|
DEVMODEW :: struct {
|
||||||
dmDeviceName: [32]wchar_t,
|
dmDeviceName: [32]wchar_t,
|
||||||
dmSpecVersion: WORD,
|
dmSpecVersion: WORD,
|
||||||
@@ -1066,8 +1193,14 @@ WS_EX_TOPMOST : UINT : 0x0000_0008
|
|||||||
WS_EX_TRANSPARENT : UINT : 0x0000_0020
|
WS_EX_TRANSPARENT : UINT : 0x0000_0020
|
||||||
WS_EX_WINDOWEDGE : UINT : 0x0000_0100
|
WS_EX_WINDOWEDGE : UINT : 0x0000_0100
|
||||||
|
|
||||||
PBS_SMOOTH :: 0x01
|
PBS_SMOOTH :: 0x01
|
||||||
PBS_VERTICAL :: 0x04
|
PBS_VERTICAL :: 0x04
|
||||||
|
PBS_MARQUEE :: 0x08
|
||||||
|
PBS_SMOOTHREVERSE :: 0x10
|
||||||
|
|
||||||
|
PBST_NORMAL :: 0x0001
|
||||||
|
PBST_ERROR :: 0x0002
|
||||||
|
PBST_PAUSED :: 0x0003
|
||||||
|
|
||||||
QS_ALLEVENTS : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY
|
QS_ALLEVENTS : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY
|
||||||
QS_ALLINPUT : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE
|
QS_ALLINPUT : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE
|
||||||
@@ -1127,6 +1260,10 @@ SWP_NOREPOSITION :: SWP_NOOWNERZORDER
|
|||||||
SWP_DEFERERASE :: 0x2000 // same as SWP_DEFERDRAWING
|
SWP_DEFERERASE :: 0x2000 // same as SWP_DEFERDRAWING
|
||||||
SWP_ASYNCWINDOWPOS :: 0x4000 // same as SWP_CREATESPB
|
SWP_ASYNCWINDOWPOS :: 0x4000 // same as SWP_CREATESPB
|
||||||
|
|
||||||
|
CSIDL_APPDATA :: 0x001a // <user name>\Application Data
|
||||||
|
CSIDL_COMMON_APPDATA :: 0x0023 // All Users\Application Data
|
||||||
|
CSIDL_PROFILE :: 0x0028 // <user name>\
|
||||||
|
|
||||||
HWND_TOP :: HWND( uintptr(0)) // 0
|
HWND_TOP :: HWND( uintptr(0)) // 0
|
||||||
HWND_BOTTOM :: HWND( uintptr(1)) // 1
|
HWND_BOTTOM :: HWND( uintptr(1)) // 1
|
||||||
HWND_TOPMOST :: HWND(~uintptr(0)) // -1
|
HWND_TOPMOST :: HWND(~uintptr(0)) // -1
|
||||||
@@ -1325,6 +1462,58 @@ WMSZ_BOTTOM :: 6
|
|||||||
WMSZ_BOTTOMLEFT :: 7
|
WMSZ_BOTTOMLEFT :: 7
|
||||||
WMSZ_BOTTOMRIGHT :: 8
|
WMSZ_BOTTOMRIGHT :: 8
|
||||||
|
|
||||||
|
// Note CLASSKEY overrides CLASSNAME
|
||||||
|
SEE_MASK_DEFAULT :: 0x00000000
|
||||||
|
SEE_MASK_CLASSNAME :: 0x00000001 // SHELLEXECUTEINFO.lpClass is valid
|
||||||
|
SEE_MASK_CLASSKEY :: 0x00000003 // SHELLEXECUTEINFO.hkeyClass is valid
|
||||||
|
// Note SEE_MASK_INVOKEIDLIST(0xC) implies SEE_MASK_IDLIST(0x04)
|
||||||
|
SEE_MASK_IDLIST :: 0x00000004 // SHELLEXECUTEINFO.lpIDList is valid
|
||||||
|
SEE_MASK_INVOKEIDLIST :: 0x0000000c // enable IContextMenu based verbs
|
||||||
|
SEE_MASK_ICON :: 0x00000010 // not used
|
||||||
|
SEE_MASK_HOTKEY :: 0x00000020 // SHELLEXECUTEINFO.dwHotKey is valid
|
||||||
|
SEE_MASK_NOCLOSEPROCESS :: 0x00000040 // SHELLEXECUTEINFO.hProcess
|
||||||
|
SEE_MASK_CONNECTNETDRV :: 0x00000080 // enables re-connecting disconnected network drives
|
||||||
|
SEE_MASK_NOASYNC :: 0x00000100 // block on the call until the invoke has completed, use for callers that exit after calling ShellExecuteEx()
|
||||||
|
SEE_MASK_FLAG_DDEWAIT :: SEE_MASK_NOASYNC // Use SEE_MASK_NOASYNC instead of SEE_MASK_FLAG_DDEWAIT as it more accuratly describes the behavior
|
||||||
|
SEE_MASK_DOENVSUBST :: 0x00000200 // indicates that SHELLEXECUTEINFO.lpFile contains env vars that should be expanded
|
||||||
|
SEE_MASK_FLAG_NO_UI :: 0x00000400 // disable UI including error messages
|
||||||
|
SEE_MASK_UNICODE :: 0x00004000
|
||||||
|
SEE_MASK_NO_CONSOLE :: 0x00008000
|
||||||
|
SEE_MASK_ASYNCOK :: 0x00100000
|
||||||
|
SEE_MASK_HMONITOR :: 0x00200000 // SHELLEXECUTEINFO.hMonitor
|
||||||
|
SEE_MASK_NOZONECHECKS :: 0x00800000
|
||||||
|
SEE_MASK_NOQUERYCLASSSTORE :: 0x01000000
|
||||||
|
SEE_MASK_WAITFORINPUTIDLE :: 0x02000000
|
||||||
|
SEE_MASK_FLAG_LOG_USAGE :: 0x04000000
|
||||||
|
|
||||||
|
// When SEE_MASK_FLAG_HINST_IS_SITE is specified SHELLEXECUTEINFO.hInstApp is used as an
|
||||||
|
// _In_ parameter and specifies a IUnknown* to be used as a site pointer. The site pointer
|
||||||
|
// is used to provide services to shell execute, the handler binding process and the verb handlers
|
||||||
|
// once they are invoked.
|
||||||
|
SEE_MASK_FLAG_HINST_IS_SITE :: 0x08000000
|
||||||
|
|
||||||
|
SHELLEXECUTEINFOW :: struct {
|
||||||
|
cbSize: DWORD, // in, required, sizeof of this structure
|
||||||
|
fMask: ULONG, // in, SEE_MASK_XXX values
|
||||||
|
hwnd: HWND, // in, optional
|
||||||
|
lpVerb: LPCWSTR, // in, optional when unspecified the default verb is choosen
|
||||||
|
lpFile: LPCWSTR, // in, either this value or lpIDList must be specified
|
||||||
|
lpParameters: LPCWSTR, // in, optional
|
||||||
|
lpDirectory: LPCWSTR, // in, optional
|
||||||
|
nShow: c.int, // in, required
|
||||||
|
hInstApp: HINSTANCE, // out when SEE_MASK_NOCLOSEPROCESS is specified
|
||||||
|
lpIDList: rawptr, // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST & SEE_MASK_INVOKEIDLIST
|
||||||
|
lpClass: LPCWSTR, // in, valid when SEE_MASK_CLASSNAME is specified
|
||||||
|
hkeyClass: HKEY, // in, valid when SEE_MASK_CLASSKEY is specified
|
||||||
|
dwHotKey: DWORD, // in, valid when SEE_MASK_HOTKEY is specified
|
||||||
|
DUMMYUNIONNAME: struct #raw_union {
|
||||||
|
hIcon: HANDLE, // not used
|
||||||
|
hMonitor: HANDLE, // in, valid when SEE_MASK_HMONITOR specified
|
||||||
|
},
|
||||||
|
hProcess: HANDLE, // out, valid when SEE_MASK_NOCLOSEPROCESS specified
|
||||||
|
}
|
||||||
|
LPSHELLEXECUTEINFOW :: ^SHELLEXECUTEINFOW
|
||||||
|
|
||||||
// Key State Masks for Mouse Messages
|
// Key State Masks for Mouse Messages
|
||||||
MK_LBUTTON :: 0x0001
|
MK_LBUTTON :: 0x0001
|
||||||
MK_RBUTTON :: 0x0002
|
MK_RBUTTON :: 0x0002
|
||||||
@@ -1366,6 +1555,25 @@ WA_INACTIVE :: 0
|
|||||||
WA_ACTIVE :: 1
|
WA_ACTIVE :: 1
|
||||||
WA_CLICKACTIVE :: 2
|
WA_CLICKACTIVE :: 2
|
||||||
|
|
||||||
|
// Struct pointed to by WM_GETMINMAXINFO lParam
|
||||||
|
MINMAXINFO :: struct {
|
||||||
|
ptReserved: POINT,
|
||||||
|
ptMaxSize: POINT,
|
||||||
|
ptMaxPosition: POINT,
|
||||||
|
ptMinTrackSize: POINT,
|
||||||
|
ptMaxTrackSize: POINT,
|
||||||
|
}
|
||||||
|
PMINMAXINFO :: ^MINMAXINFO
|
||||||
|
LPMINMAXINFO :: PMINMAXINFO
|
||||||
|
|
||||||
|
MONITORINFO :: struct {
|
||||||
|
cbSize: DWORD,
|
||||||
|
rcMonitor: RECT,
|
||||||
|
rcWork: RECT,
|
||||||
|
dwFlags: DWORD,
|
||||||
|
}
|
||||||
|
LPMONITORINFO :: ^MONITORINFO
|
||||||
|
|
||||||
// SetWindowsHook() codes
|
// SetWindowsHook() codes
|
||||||
WH_MIN :: -1
|
WH_MIN :: -1
|
||||||
WH_MSGFILTER :: -1
|
WH_MSGFILTER :: -1
|
||||||
@@ -1462,6 +1670,24 @@ IDI_WARNING := IDI_EXCLAMATION
|
|||||||
IDI_ERROR := IDI_HAND
|
IDI_ERROR := IDI_HAND
|
||||||
IDI_INFORMATION := IDI_ASTERISK
|
IDI_INFORMATION := IDI_ASTERISK
|
||||||
|
|
||||||
|
IMAGE_BITMAP :: 0
|
||||||
|
IMAGE_ICON :: 1
|
||||||
|
IMAGE_CURSOR :: 2
|
||||||
|
IMAGE_ENHMETAFILE :: 3
|
||||||
|
|
||||||
|
LR_DEFAULTCOLOR :: 0x00000000
|
||||||
|
LR_MONOCHROME :: 0x00000001
|
||||||
|
LR_COLOR :: 0x00000002
|
||||||
|
LR_COPYRETURNORG :: 0x00000004
|
||||||
|
LR_COPYDELETEORG :: 0x00000008
|
||||||
|
LR_LOADFROMFILE :: 0x00000010
|
||||||
|
LR_LOADTRANSPARENT :: 0x00000020
|
||||||
|
LR_DEFAULTSIZE :: 0x00000040
|
||||||
|
LR_VGACOLOR :: 0x00000080
|
||||||
|
LR_LOADMAP3DCOLORS :: 0x00001000
|
||||||
|
LR_CREATEDIBSECTION :: 0x00002000
|
||||||
|
LR_COPYFROMRESOURCE :: 0x00004000
|
||||||
|
LR_SHARED :: 0x00008000
|
||||||
|
|
||||||
// DIB color table identifiers
|
// DIB color table identifiers
|
||||||
DIB_RGB_COLORS :: 0
|
DIB_RGB_COLORS :: 0
|
||||||
@@ -1774,12 +2000,15 @@ WAIT_FAILED: DWORD : 0xFFFFFFFF
|
|||||||
|
|
||||||
PIPE_ACCESS_INBOUND: DWORD : 0x00000001
|
PIPE_ACCESS_INBOUND: DWORD : 0x00000001
|
||||||
PIPE_ACCESS_OUTBOUND: DWORD : 0x00000002
|
PIPE_ACCESS_OUTBOUND: DWORD : 0x00000002
|
||||||
|
PIPE_ACCESS_DUPLEX: DWORD : 0x00000003
|
||||||
FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000
|
FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000
|
||||||
FILE_FLAG_OVERLAPPED: DWORD : 0x40000000
|
FILE_FLAG_OVERLAPPED: DWORD : 0x40000000
|
||||||
PIPE_WAIT: DWORD : 0x00000000
|
PIPE_WAIT: DWORD : 0x00000000
|
||||||
PIPE_TYPE_BYTE: DWORD : 0x00000000
|
PIPE_TYPE_BYTE: DWORD : 0x00000000
|
||||||
|
PIPE_TYPE_MESSAGE: DWORD : 0x00000004
|
||||||
PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008
|
PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008
|
||||||
PIPE_READMODE_BYTE: DWORD : 0x00000000
|
PIPE_READMODE_BYTE: DWORD : 0x00000000
|
||||||
|
PIPE_READMODE_MESSAGE: DWORD : 0x00000002
|
||||||
PIPE_ACCEPT_REMOTE_CLIENTS: DWORD : 0x00000000
|
PIPE_ACCEPT_REMOTE_CLIENTS: DWORD : 0x00000000
|
||||||
|
|
||||||
FD_SETSIZE :: 64
|
FD_SETSIZE :: 64
|
||||||
@@ -1793,7 +2022,58 @@ HEAP_ZERO_MEMORY: DWORD : 0x00000008
|
|||||||
HANDLE_FLAG_INHERIT: DWORD : 0x00000001
|
HANDLE_FLAG_INHERIT: DWORD : 0x00000001
|
||||||
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 0x00000002
|
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 0x00000002
|
||||||
|
|
||||||
TOKEN_READ: DWORD : 0x20008
|
GENERIC_MAPPING :: struct {
|
||||||
|
GenericRead: ACCESS_MASK,
|
||||||
|
GenericWrite: ACCESS_MASK,
|
||||||
|
GenericExecute: ACCESS_MASK,
|
||||||
|
GenericAll: ACCESS_MASK,
|
||||||
|
}
|
||||||
|
PGENERIC_MAPPING :: ^GENERIC_MAPPING
|
||||||
|
|
||||||
|
SECURITY_IMPERSONATION_LEVEL :: enum {
|
||||||
|
SecurityAnonymous,
|
||||||
|
SecurityIdentification,
|
||||||
|
SecurityImpersonation,
|
||||||
|
SecurityDelegation,
|
||||||
|
}
|
||||||
|
|
||||||
|
SECURITY_INFORMATION :: DWORD
|
||||||
|
ANYSIZE_ARRAY :: 1
|
||||||
|
|
||||||
|
LUID_AND_ATTRIBUTES :: struct {
|
||||||
|
Luid: LUID,
|
||||||
|
Attributes: DWORD,
|
||||||
|
}
|
||||||
|
|
||||||
|
PRIVILEGE_SET :: struct {
|
||||||
|
PrivilegeCount: DWORD,
|
||||||
|
Control: DWORD,
|
||||||
|
Privilege: [ANYSIZE_ARRAY]LUID_AND_ATTRIBUTES,
|
||||||
|
}
|
||||||
|
PPRIVILEGE_SET :: ^PRIVILEGE_SET
|
||||||
|
|
||||||
|
// Token Specific Access Rights.
|
||||||
|
TOKEN_ASSIGN_PRIMARY :: 0x0001
|
||||||
|
TOKEN_DUPLICATE :: 0x0002
|
||||||
|
TOKEN_IMPERSONATE :: 0x0004
|
||||||
|
TOKEN_QUERY :: 0x0008
|
||||||
|
TOKEN_QUERY_SOURCE :: 0x0010
|
||||||
|
TOKEN_ADJUST_PRIVILEGES :: 0x0020
|
||||||
|
TOKEN_ADJUST_GROUPS :: 0x0040
|
||||||
|
TOKEN_ADJUST_DEFAULT :: 0x0080
|
||||||
|
TOKEN_ADJUST_SESSIONID :: 0x0100
|
||||||
|
|
||||||
|
TOKEN_ALL_ACCESS_P :: STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY |\
|
||||||
|
TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT
|
||||||
|
|
||||||
|
TOKEN_ALL_ACCESS :: TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID
|
||||||
|
TOKEN_READ :: STANDARD_RIGHTS_READ | TOKEN_QUERY
|
||||||
|
TOKEN_WRITE :: STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT
|
||||||
|
TOKEN_EXECUTE :: STANDARD_RIGHTS_EXECUTE
|
||||||
|
TOKEN_TRUST_CONSTRAINT_MASK :: STANDARD_RIGHTS_READ | TOKEN_QUERY | TOKEN_QUERY_SOURCE
|
||||||
|
TOKEN_ACCESS_PSEUDO_HANDLE_WIN8 :: TOKEN_QUERY | TOKEN_QUERY_SOURCE
|
||||||
|
TOKEN_ACCESS_PSEUDO_HANDLE :: TOKEN_ACCESS_PSEUDO_HANDLE_WIN8
|
||||||
|
|
||||||
|
|
||||||
CP_ACP :: 0 // default to ANSI code page
|
CP_ACP :: 0 // default to ANSI code page
|
||||||
CP_OEMCP :: 1 // default to OEM code page
|
CP_OEMCP :: 1 // default to OEM code page
|
||||||
@@ -2101,9 +2381,10 @@ FILETIME :: struct {
|
|||||||
|
|
||||||
FILETIME_as_unix_nanoseconds :: proc "contextless" (ft: FILETIME) -> i64 {
|
FILETIME_as_unix_nanoseconds :: proc "contextless" (ft: FILETIME) -> i64 {
|
||||||
t := i64(u64(ft.dwLowDateTime) | u64(ft.dwHighDateTime) << 32)
|
t := i64(u64(ft.dwLowDateTime) | u64(ft.dwHighDateTime) << 32)
|
||||||
return (t - 0x019db1ded53e8000) * 100
|
return (t - 116444736000000000) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OVERLAPPED :: struct {
|
OVERLAPPED :: struct {
|
||||||
Internal: ^c_ulong,
|
Internal: ^c_ulong,
|
||||||
InternalHigh: ^c_ulong,
|
InternalHigh: ^c_ulong,
|
||||||
@@ -2777,6 +3058,16 @@ SYSTEMTIME :: struct {
|
|||||||
milliseconds: WORD,
|
milliseconds: WORD,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TIME_ZONE_INFORMATION :: struct {
|
||||||
|
Bias: LONG,
|
||||||
|
StandardName: [32]WCHAR,
|
||||||
|
StandardDate: SYSTEMTIME,
|
||||||
|
StandardBias: LONG,
|
||||||
|
DaylightName: [32]WCHAR,
|
||||||
|
DaylightDate: SYSTEMTIME,
|
||||||
|
DaylightBias: LONG,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
IMAGE_DOS_HEADER :: struct {
|
IMAGE_DOS_HEADER :: struct {
|
||||||
@@ -3048,12 +3339,32 @@ SHCONTF_FLATLIST :: 0x4000
|
|||||||
SHCONTF_ENABLE_ASYNC :: 0x8000
|
SHCONTF_ENABLE_ASYNC :: 0x8000
|
||||||
SHCONTF_INCLUDESUPERHIDDEN :: 0x10000
|
SHCONTF_INCLUDESUPERHIDDEN :: 0x10000
|
||||||
|
|
||||||
|
SHACF_DEFAULT :: 0x00000000 // Currently (SHACF_FILESYSTEM | SHACF_URLALL)
|
||||||
|
SHACF_FILESYSTEM :: 0x00000001 // This includes the File System as well as the rest of the shell (Desktop\My Computer\Control Panel\)
|
||||||
|
SHACF_URLALL :: (SHACF_URLHISTORY | SHACF_URLMRU)
|
||||||
|
SHACF_URLHISTORY :: 0x00000002 // URLs in the User's History
|
||||||
|
SHACF_URLMRU :: 0x00000004 // URLs in the User's Recently Used list.
|
||||||
|
SHACF_USETAB :: 0x00000008 // Use the tab to move thru the autocomplete possibilities instead of to the next dialog/window control.
|
||||||
|
SHACF_FILESYS_ONLY :: 0x00000010 // This includes the File System
|
||||||
|
SHACF_FILESYS_DIRS :: 0x00000020 // Same as SHACF_FILESYS_ONLY except it only includes directories, UNC servers, and UNC server shares.
|
||||||
|
SHACF_VIRTUAL_NAMESPACE :: 0x00000040 // Also include the virtual namespace
|
||||||
|
SHACF_AUTOSUGGEST_FORCE_ON :: 0x10000000 // Ignore the registry default and force the feature on.
|
||||||
|
SHACF_AUTOSUGGEST_FORCE_OFF :: 0x20000000 // Ignore the registry default and force the feature off.
|
||||||
|
SHACF_AUTOAPPEND_FORCE_ON :: 0x40000000 // Ignore the registry default and force the feature on. (Also know as AutoComplete)
|
||||||
|
SHACF_AUTOAPPEND_FORCE_OFF :: 0x80000000 // Ignore the registry default and force the feature off. (Also know as AutoComplete)
|
||||||
|
|
||||||
|
LWSTDAPI :: HRESULT
|
||||||
|
|
||||||
CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}}
|
CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}}
|
||||||
CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}}
|
CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}}
|
||||||
|
CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
|
||||||
|
|
||||||
IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}}
|
IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}}
|
||||||
IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}}
|
IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}}
|
||||||
IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}}
|
IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}}
|
||||||
|
IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
|
||||||
|
IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}}
|
||||||
|
IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}}
|
||||||
|
|
||||||
IModalWindow :: struct #raw_union {
|
IModalWindow :: struct #raw_union {
|
||||||
#subtype IUnknown: IUnknown,
|
#subtype IUnknown: IUnknown,
|
||||||
@@ -3358,6 +3669,84 @@ IFileSaveDialogVtbl :: struct {
|
|||||||
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
|
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ITaskbarList :: struct #raw_union {
|
||||||
|
#subtype IUnknown: IUnknown,
|
||||||
|
using Vtbl: ^ITaskbarListVtbl,
|
||||||
|
}
|
||||||
|
ITaskbarListVtbl :: struct {
|
||||||
|
using IUnknownVtbl: IUnknownVtbl,
|
||||||
|
HrInit: proc "stdcall" (this: ^ITaskbarList) -> HRESULT,
|
||||||
|
AddTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
DeleteTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
ActivateTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
SetActiveAlt: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
}
|
||||||
|
|
||||||
|
ITaskbarList2 :: struct #raw_union {
|
||||||
|
#subtype ITaskbarList: ITaskbarList,
|
||||||
|
using Vtbl: ^ITaskbarList2Vtbl,
|
||||||
|
}
|
||||||
|
ITaskbarList2Vtbl :: struct {
|
||||||
|
using ITaskbarListVtbl: ITaskbarListVtbl,
|
||||||
|
MarkFullscreenWindow: proc "stdcall" (this: ^ITaskbarList2, hwnd: HWND, fFullscreen: BOOL) -> HRESULT,
|
||||||
|
}
|
||||||
|
|
||||||
|
TBPFLAG :: enum c_int {
|
||||||
|
NOPROGRESS = 0,
|
||||||
|
INDETERMINATE = 0x1,
|
||||||
|
NORMAL = 0x2,
|
||||||
|
ERROR = 0x4,
|
||||||
|
PAUSED = 0x8,
|
||||||
|
}
|
||||||
|
|
||||||
|
THUMBBUTTONFLAGS :: enum c_int {
|
||||||
|
ENABLED = 0,
|
||||||
|
DISABLED = 0x1,
|
||||||
|
DISMISSONCLICK = 0x2,
|
||||||
|
NOBACKGROUND = 0x4,
|
||||||
|
HIDDEN = 0x8,
|
||||||
|
NONINTERACTIVE = 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
THUMBBUTTONMASK :: enum c_int {
|
||||||
|
BITMAP = 0x1,
|
||||||
|
ICON = 0x2,
|
||||||
|
TOOLTIP = 0x4,
|
||||||
|
FLAGS = 0x8,
|
||||||
|
}
|
||||||
|
|
||||||
|
THUMBBUTTON :: struct {
|
||||||
|
dwMask: THUMBBUTTONMASK,
|
||||||
|
iId: UINT,
|
||||||
|
iBitmap: UINT,
|
||||||
|
hIcon: HICON,
|
||||||
|
szTip: [260]WCHAR,
|
||||||
|
dwFlags: THUMBBUTTONFLAGS,
|
||||||
|
}
|
||||||
|
LPTHUMBBUTTON :: ^THUMBBUTTON
|
||||||
|
|
||||||
|
HIMAGELIST :: ^IUnknown
|
||||||
|
|
||||||
|
ITaskbarList3 :: struct #raw_union {
|
||||||
|
#subtype ITaskbarList2: ITaskbarList2,
|
||||||
|
using Vtbl: ^ITaskbarList3Vtbl,
|
||||||
|
}
|
||||||
|
ITaskbarList3Vtbl :: struct {
|
||||||
|
using ITaskbarList2Vtbl: ITaskbarList2Vtbl,
|
||||||
|
SetProgressValue: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, ullCompleted: ULONGLONG, ullTotal: ULONGLONG) -> HRESULT,
|
||||||
|
SetProgressState: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, tbpFlags: TBPFLAG) -> HRESULT,
|
||||||
|
RegisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND) -> HRESULT,
|
||||||
|
UnregisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND) -> HRESULT,
|
||||||
|
SetTabOrder: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndInsertBefore: HWND) -> HRESULT,
|
||||||
|
SetTabActive: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND, dwReserved: DWORD) -> HRESULT,
|
||||||
|
ThumbBarAddButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT,
|
||||||
|
ThumbBarUpdateButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT,
|
||||||
|
ThumbBarSetImageList: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, himl: HIMAGELIST) -> HRESULT,
|
||||||
|
SetOverlayIcon: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, hIcon: HICON, pszDescription: LPCWSTR) -> HRESULT,
|
||||||
|
SetThumbnailTooltip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, pszTip: LPCWSTR) -> HRESULT,
|
||||||
|
SetThumbnailClip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, prcClip: ^RECT) -> HRESULT,
|
||||||
|
}
|
||||||
|
|
||||||
MEMORYSTATUSEX :: struct {
|
MEMORYSTATUSEX :: struct {
|
||||||
dwLength: DWORD,
|
dwLength: DWORD,
|
||||||
dwMemoryLoad: DWORD,
|
dwMemoryLoad: DWORD,
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ foreign user32 {
|
|||||||
LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON ---
|
LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON ---
|
||||||
LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR ---
|
LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR ---
|
||||||
LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR ---
|
LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR ---
|
||||||
|
LoadImageW :: proc(hInst: HINSTANCE, name: LPCWSTR, type: UINT, cx: c_int, cy: c_int, fuLoad: UINT) -> HANDLE ---
|
||||||
|
|
||||||
GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL ---
|
GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL ---
|
||||||
GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL ---
|
GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL ---
|
||||||
@@ -99,6 +100,7 @@ foreign user32 {
|
|||||||
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
|
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
|
||||||
|
|
||||||
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
|
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
|
||||||
|
GetMonitorInfoW :: proc(hMonitor: HMONITOR, lpmi: LPMONITORINFO) -> BOOL ---
|
||||||
|
|
||||||
GetWindowDC :: proc(hWnd: HWND) -> HDC ---
|
GetWindowDC :: proc(hWnd: HWND) -> HDC ---
|
||||||
GetDC :: proc(hWnd: HWND) -> HDC ---
|
GetDC :: proc(hWnd: HWND) -> HDC ---
|
||||||
@@ -121,6 +123,8 @@ foreign user32 {
|
|||||||
|
|
||||||
GetKeyState :: proc(nVirtKey: c_int) -> SHORT ---
|
GetKeyState :: proc(nVirtKey: c_int) -> SHORT ---
|
||||||
GetAsyncKeyState :: proc(vKey: c_int) -> SHORT ---
|
GetAsyncKeyState :: proc(vKey: c_int) -> SHORT ---
|
||||||
|
|
||||||
|
GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL ---
|
||||||
|
|
||||||
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
|
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
|
||||||
|
|
||||||
@@ -201,6 +205,17 @@ foreign user32 {
|
|||||||
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||||
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||||
RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
|
RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
|
||||||
|
|
||||||
|
SetLayeredWindowAttributes :: proc(hWnd: HWND, crKey: COLORREF, bAlpha: BYTE, dwFlags: DWORD) -> BOOL ---
|
||||||
|
|
||||||
|
FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> int ---
|
||||||
|
EqualRect :: proc(lprc1: ^RECT, lprc2: ^RECT) -> BOOL ---
|
||||||
|
|
||||||
|
GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL ---
|
||||||
|
GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
|
||||||
|
SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
|
||||||
|
CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
|
||||||
|
GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateWindowW :: #force_inline proc "stdcall" (
|
CreateWindowW :: #force_inline proc "stdcall" (
|
||||||
@@ -431,3 +446,27 @@ RI_MOUSE_BUTTON_5_DOWN :: 0x0100
|
|||||||
RI_MOUSE_BUTTON_5_UP :: 0x0200
|
RI_MOUSE_BUTTON_5_UP :: 0x0200
|
||||||
RI_MOUSE_WHEEL :: 0x0400
|
RI_MOUSE_WHEEL :: 0x0400
|
||||||
RI_MOUSE_HWHEEL :: 0x0800
|
RI_MOUSE_HWHEEL :: 0x0800
|
||||||
|
|
||||||
|
WINDOWPLACEMENT :: struct {
|
||||||
|
length: UINT,
|
||||||
|
flags: UINT,
|
||||||
|
showCmd: UINT,
|
||||||
|
ptMinPosition: POINT,
|
||||||
|
ptMaxPosition: POINT,
|
||||||
|
rcNormalPosition: RECT,
|
||||||
|
rcDevice: RECT,
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOWINFO :: struct {
|
||||||
|
cbSize: DWORD,
|
||||||
|
rcWindow: RECT,
|
||||||
|
rcClient: RECT,
|
||||||
|
dwStyle: DWORD,
|
||||||
|
dwExStyle: DWORD,
|
||||||
|
dwWindowStatus: DWORD,
|
||||||
|
cxWindowBorders: UINT,
|
||||||
|
cyWindowBorders: UINT,
|
||||||
|
atomWindowType: ATOM,
|
||||||
|
wCreatorVersion: WORD,
|
||||||
|
}
|
||||||
|
PWINDOWINFO :: ^WINDOWINFO
|
||||||
@@ -62,19 +62,19 @@ utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstri
|
|||||||
wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) {
|
wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
if N <= 0 {
|
if N == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil)
|
n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N) if N > 0 else -1, nil, 0, nil, nil)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If N == -1 the call to WideCharToMultiByte assume the wide string is null terminated
|
// If N < 0 the call to WideCharToMultiByte assume the wide string is null terminated
|
||||||
// and will scan it to find the first null terminated character. The resulting string will
|
// and will scan it to find the first null terminated character. The resulting string will
|
||||||
// also be null terminated.
|
// also be null terminated.
|
||||||
// If N != -1 it assumes the wide string is not null terminated and the resulting string
|
// If N > 0 it assumes the wide string is not null terminated and the resulting string
|
||||||
// will not be null terminated.
|
// will not be null terminated.
|
||||||
text := make([]byte, n) or_return
|
text := make([]byte, n) or_return
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// +build windows
|
||||||
|
package sys_windows
|
||||||
|
|
||||||
|
foreign import uxtheme "system:UxTheme.lib"
|
||||||
|
|
||||||
|
MARGINS :: distinct [4]int
|
||||||
|
PMARGINS :: ^MARGINS
|
||||||
|
|
||||||
|
@(default_calling_convention="stdcall")
|
||||||
|
foreign uxtheme {
|
||||||
|
IsThemeActive :: proc() -> BOOL ---
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user