Compare commits

..

2465 Commits

Author SHA1 Message Date
Jeroen van Rijn df233aee94 Merge pull request #1760 from Kelimion/xxh3_fix
[xxh3] Fix flaws in streaming implementation
2022-05-01 12:54:20 +02:00
Jeroen van Rijn 335b724209 [xxh3] Fix flaws in streaming implementation 2022-05-01 12:47:05 +02:00
Jeroen van Rijn 6ade9acc4d [pbm] Remove stray comment. 2022-04-30 22:54:53 +02:00
Jeroen van Rijn 2081f8fcd6 [tests/core/image] Remove old crappy PPM writer. 2022-04-30 22:04:47 +02:00
Jeroen van Rijn 964ab4814c Merge pull request #1726 from WalterPlinge/image-netpbm
Add Netpbm image format support
2022-04-30 22:01:22 +02:00
Jeroen van Rijn 7a032cf9f9 [pbm] Also test PFM formats. 2022-04-30 21:57:14 +02:00
Jeroen van Rijn 694c13fe86 Merge branch 'master' into pr/1726 2022-04-30 21:01:04 +02:00
Jeroen van Rijn 8bd16c32f3 [pbm] Fixes. 2022-04-30 21:00:32 +02:00
Jeroen van Rijn 234d529867 [pbm] WIP unit tests. part deux. 2022-04-30 19:25:16 +02:00
Jeroen van Rijn dd8b71e353 [pbm] WIP unit tests. 2022-04-30 17:52:23 +02:00
Jeroen van Rijn 41a18f078d Merge pull request #1757 from Kelimion/xml
[xml] Add `parse_from_string` overload.
2022-04-30 14:51:46 +02:00
Jeroen van Rijn 3978e7e1ca [xml] Add parse_from_string overload.
`parse` now takes either a `[]u8` slice or a string.
`load_from_file` takes a path string.
2022-04-30 14:43:58 +02:00
gingerBill b758c696f2 Merge pull request #1746 from odin-lang/sync-cond-futex
`core:sync` Improvements
2022-04-30 13:34:16 +01:00
Jeroen van Rijn d6a8216ce4 [pbm] Normalize some errors, correct .depth 2022-04-30 14:34:07 +02:00
gingerBill 2720f64c06 Remove unused imports 2022-04-30 13:28:45 +01:00
gingerBill de2ebdd5cc Merge pull request #1753 from awwdev/master
Fixing some typos in vendor:OpenGL
2022-04-30 13:28:02 +01:00
gingerBill 4e39629a9a Unify implementation for *nix platforms 2022-04-30 13:09:24 +01:00
gingerBill 78a8da5fea Add sync.Parker 2022-04-30 12:37:39 +01:00
gingerBill d5886c1572 Remove the wait group based semaphore implementation
It was a misuse of the data structure
2022-04-30 12:37:14 +01:00
Jeroen van Rijn 7cc759a855 Merge pull request #1756 from ftphikari/master
sys/windows: add a couple of procedures and types
2022-04-30 12:46:11 +02:00
gingerBill dd6337224f Correct explicit atomic orderings 2022-04-30 11:42:28 +01:00
hikari d2bac0c35e sys/windows: fix build issues 2022-04-30 13:40:38 +03:00
hikari 8c7f3fd1e6 sys/windows: change macro and add comment 2022-04-30 13:34:11 +03:00
Jeroen van Rijn ae3deea153 Merge branch 'master' into pr/1726 2022-04-30 12:29:28 +02:00
hikari 40bea95fb0 sys/windows: add GetDCBrushColor 2022-04-30 12:41:04 +03:00
hikari 0ad448f1c7 sys/windows: add a couple of procedures and types 2022-04-30 11:21:37 +03:00
Jeroen van Rijn 9c9c2b483c [i18n] Enable *nix tests again. 2022-04-29 18:41:21 +02:00
Jeroen van Rijn 819345caa6 Disable i18n test for *nix for now. 2022-04-29 18:28:42 +02:00
Jeroen van Rijn 11ceb3973d Merge pull request #1754 from Kelimion/i18n
[i18n] Fix segfault on cleanup on Linux
2022-04-29 18:20:54 +02:00
Jeroen van Rijn 36263399a0 [i18n] Enable i18n test on Linux. 2022-04-29 18:13:46 +02:00
Jeroen van Rijn ff0f0c447f [i18n] Fix segfault on destroy on Linux
Forgot to intern the section string in QT TS loader.
2022-04-29 18:10:13 +02:00
Jeroen van Rijn aa681932a9 Merge pull request #1336 from Kelimion/i18n
[i18n] Initial i18n support.
2022-04-29 16:27:28 +02:00
Jeroen van Rijn 09e1c0fa27 [i18n] Add tests. 2022-04-29 16:19:13 +02:00
Jeroen van Rijn 957ef8e8fe [i18n/xml] Move I18N XML files to their own assets directory. 2022-04-29 13:16:30 +02:00
Jeroen van Rijn 2e11a8da5b [i18n] Move to core:text/i18n. 2022-04-29 13:02:40 +02:00
awwdev e9cfcf9ecc fix typo in TexImage3D 2022-04-29 11:26:57 +02:00
awwdev 789ab99c4d replaced a few [^]u8 with cstring 2022-04-29 11:21:23 +02:00
Jeroen van Rijn 0297db6f2e Merge pull request #1752 from sduman/patch-1
Add missing result parameter names
2022-04-29 01:21:35 +02:00
sduman 9ce64916e6 Add missing result parameter names
This adds some missing result parameters names back to pop_front_safe.

Currently it the procedure won't compile since it's referencing missing variable names.
2022-04-28 17:08:48 -06:00
Jeroen van Rijn 1289c96e2c [i18n] QT Linguist TS reader. 2022-04-29 00:29:55 +02:00
Jeroen van Rijn ba23bfb7b9 [i18n] Allow multiple sections. 2022-04-28 20:12:32 +02:00
Jeroen van Rijn 2fae6eda23 [i18n] Initial i18n support.
- Add initial GetText .MO parser
- Add translation struct and helpers
- Pluralized lookup

 TODO:
- Support for more translation catalog file formats.
2022-04-28 18:58:49 +02:00
Jeroen van Rijn e53ba3b116 Allow -error-pos-style:default as an alias for odin 2022-04-28 18:18:25 +02:00
Jeroen van Rijn 1ed84a064b Make -error-pos-style case-insensitive. 2022-04-28 18:12:55 +02:00
Jeroen van Rijn 79019c7a09 Merge pull request #1751 from Kelimion/error-pos-style
Fix -error-pos-style:unix
2022-04-28 17:52:47 +02:00
Jeroen van Rijn a1002e6960 Fix -error-pos-style:unix 2022-04-28 17:46:36 +02:00
Jeroen van Rijn 62139cb5a4 Merge pull request #1342 from Kelimion/xml
Initial version of `core:encoding/xml`.
2022-04-28 15:54:28 +02:00
Jeroen van Rijn 127b0ba65e [xml] Enable tests. 2022-04-28 15:46:36 +02:00
Jeroen van Rijn 80878264b6 [xml] Speedup. 2022-04-28 15:29:00 +02:00
gingerBill 9fcba99ca2 Merge pull request #1749 from karl-zylinski/d3d12-binding-fixes
D3D12 binding fixes
2022-04-27 22:16:24 +01:00
Karl Zylinski 03c9212600 Added some additional IID versions of Direct3D 12 UUIDs that I missed during my first pass. All are accounted for now. 2022-04-27 22:30:28 +02:00
Karl Zylinski 5650087aa3 Merge remote-tracking branch 'origin/master' into d3d12-binding-fixes 2022-04-27 20:50:54 +02:00
Karl Zylinski 67689ecb21 Typo fix in d3d12.odin 2022-04-27 20:47:05 +02:00
Karl Zylinski cd13dedb36 D3D12 binding fixes: Added dxgi.IID versions of all the UUIDs in d3d12.odin so that the IIDs can be used to fetch interfaces properly. Also fixed an issue where GetDesc, GetCPUDescriptorHandleForHeapStart and GetGPUDescriptorHandleForHeapStart had the wrong signature due to an old D3D12 header bug, more info: https://stackoverflow.com/questions/34118929/getcpudescriptorhandleforheapstart-stack-corruption 2022-04-27 20:12:44 +02:00
gingerBill 10cd294cf2 Use Acquire semantics for the futex_wait load shortcut 2022-04-27 15:57:47 +01:00
gingerBill d6cfb60506 Remove prev from Atomic_Cond 2022-04-27 15:29:21 +01:00
gingerBill df0df73540 Merge branch 'master' into sync-cond-futex 2022-04-27 15:26:21 +01:00
gingerBill 33f1418dec Merge branch 'master' of https://github.com/odin-lang/Odin 2022-04-27 15:26:02 +01:00
gingerBill 305510bea0 Update intrinsics.odin 2022-04-27 15:25:56 +01:00
gingerBill beb698f31d Merge branch 'master' into sync-cond-futex 2022-04-27 15:21:18 +01:00
Jeroen van Rijn 6df21d6a9f Merge branch 'master' into xml 2022-04-27 16:13:47 +02:00
Jeroen van Rijn c5982e52d5 Merge pull request #1748 from Kelimion/test-assets
Move Odin CI test assets over to its own repository.
2022-04-27 16:04:15 +02:00
gingerBill bd73b2845b Unify default Sema and Atomic_Sema behaviour 2022-04-27 15:03:48 +01:00
Jeroen van Rijn da0f722aad Move Odin CI test assets over to its own repository. 2022-04-27 15:56:45 +02:00
gingerBill 904f0407f8 Add intrinsics.type_is_multi_pointer 2022-04-27 14:53:26 +01:00
gingerBill fbbb0d7610 Update intrinsics.odin for documentation 2022-04-27 14:51:04 +01:00
gingerBill 3a9b0a22e7 Add core:container/intrusive/list 2022-04-27 14:27:33 +01:00
Jeroen van Rijn c4e0d1efa1 Merge branch 'master' into xml 2022-04-27 14:37:15 +02:00
gingerBill 9349dfba8f Add new builtin container_of 2022-04-27 12:39:45 +01:00
gingerBill 9692496989 Add intrinsics.type_field_type 2022-04-27 12:27:53 +01:00
gingerBill a6cef2e50e Update LICENSE 2022-04-26 21:47:45 +01:00
Jeroen van Rijn d262eda91c Update Makefile 2022-04-26 15:10:31 +02:00
Jeroen van Rijn 40f0f5ad8d Update CI for math library. 2022-04-26 15:01:09 +02:00
Jeroen van Rijn 1c03e68057 Update CI. 2022-04-26 14:56:28 +02:00
Jeroen van Rijn f1c1cfb6d2 Merge pull request #1747 from Kelimion/filename-merge
Filename generation
2022-04-26 14:52:58 +02:00
Jeroen van Rijn ba5e33bc35 Update CI workflow. 2022-04-26 14:51:16 +02:00
gingerBill 80df9fbc65 Merge pull request #1745 from eisbehr/patch-1
Make allocator in pool_add_task() explicit
2022-04-26 13:49:44 +01:00
Jeroen van Rijn b68ab0dd6d Merge branch 'master' into filename-merge 2022-04-26 14:45:00 +02:00
gingerBill 9cf7a31068 Implement _Sema with Atomic_Sema 2022-04-26 13:44:32 +01:00
Jeroen van Rijn 5e11ad2e1e Update test paths. 2022-04-26 14:23:23 +02:00
gingerBill 07d1a42768 Simplify Atomic_Sema implementation 2022-04-26 13:11:34 +01:00
gingerBill ec8221cb5d Simplify Atomic_Cond implementation 2022-04-26 13:04:50 +01:00
Jeroen van Rijn a5342a0126 Address edge cases. 2022-04-26 13:14:09 +02:00
gingerBill c81fd2e5dd Fix #1644 2022-04-26 11:45:46 +01:00
gingerBill 3bd7122959 Fix #1720 2022-04-26 11:42:01 +01:00
gingerBill 530401e5ee Fix #1729 2022-04-26 11:38:32 +01:00
gingerBill a412d34574 Fix #1740 2022-04-26 11:35:34 +01:00
Florian Behr ee67a0b9a1 reorder procedure parameters to make sure the optional argument in pool_add_task() is last, and the argument order is consistent with pool_init() 2022-04-25 14:08:09 +02:00
Florian Behr ca6a1db757 fix doc comment for pool_init 2022-04-25 13:41:39 +02:00
Florian Behr 1fb76ad768 change usage in demo.odin 2022-04-25 13:41:19 +02:00
Florian Behr e01662c139 Make allocator in pool_add_task() explicit 2022-04-25 13:23:05 +02:00
Jeroen van Rijn 63331ef731 Revert "Merge pull request #1702 from Kelimion/filename_generation"
This reverts commit a40a53b104, reversing
changes made to 5422a3b17e.
2022-04-24 19:53:36 +02:00
Jeroen van Rijn a40a53b104 Merge pull request #1702 from Kelimion/filename_generation
Compiler: Add early error for output path being a directory.
2022-04-24 15:15:51 +02:00
Jeroen van Rijn 9f8d90f466 Update CI paths for issue tests. 2022-04-24 14:28:00 +02:00
Jeroen van Rijn 3d2856db31 Update tests to use new filename generation code. 2022-04-24 14:19:25 +02:00
Jeroen van Rijn f4723aea4c Remove redundant bit for non-Windows. 2022-04-24 13:37:26 +02:00
Jeroen van Rijn 76d48b38d3 Compiler: Allow -out: to not have an extension on *nix for executables (only). 2022-04-24 13:37:26 +02:00
Jeroen van Rijn 3cab2592c3 Compiler: Add early error for output path being a directory.
- Introduce new `Path` type and an array of build paths on the build context.
- Resolve input and output paths/files early (before parsing).
- Error early if inputs are missing or outputs are directories.
- Plumb new file path generation into linker stage instead of its adhoc method.

TODO:
- Remove more adhoc file path generation in parser and linker stage.
- Make intermediate object file generation use new path system.
- Round out and robustify Path helper functions.
2022-04-24 13:37:26 +02:00
Jeroen van Rijn 5422a3b17e Merge pull request #1743 from Tetralux/filepath-stems
[path/filepath] Add file stem and long-extension procedures
2022-04-23 22:33:31 +02:00
Tetralux b44b6e7e50 [path/filepath] Add file stem and long-extension procedures
Adds stem(), short_stem(), and long_ext(); also adds doc-comments to base() and ext().

The 'stem' is usually 'the name' of the file; the basename without the file extension.
To this end, this adds stem(), which is such that:

	stem(path) + ext(path) = base(path)

However, 'file extension' has two different meanings to what constitutes it!

 > What is the extension of: 'name.tar.gz' ?

Colloquially, you would likely think of it as 'a tarball' - which you might think is '.tar.gz'.
But, if you're writing code to process a file of this type, you would first treat it
as a Gzip file, and then treat the result as a TAR file - i.e: '.gz' ... _followed by_ '.tar'.

ext() returns '.gz' here, since that is the most-immediate format that you would need to use
to decode it; it would be a Gzip stream.

Sometimes though, you do actually want to consider these longer file extensions.

Perhaps you're extracting a tarball, and what to know what to call the intermediate tar file;
perhaps you want to check to see if this file is a tarball, or just a Gzip file;
or maybe you just want 'the name' of the file, and not this "strange 'name-and-part-of-the-extension' thing".

So, this also adds short_stem() and long_ext(), such that:

	short_stem(path) + long_ext(path) = base(path)

Thus, we can use either, but the most immediately-useful one is the easiest to reach for:

      stem('name.tar.gz') -> 'name.tar'
       ext('name.tar.gz') -> '.gz'

short_stem('name.tar.gz') -> 'name'
  long_ext('name.tar.gz') -> '.tar.gz'

These procedures are identical to their counterparts when the path only has a simple extension:

      stem('name.txt') -> 'name'
       ext('name.txt') -> '.txt'

short_stem('name.txt') -> 'name'
  long_ext('name.txt') -> '.txt'
2022-04-23 20:25:59 +00:00
Jeroen van Rijn 849efff070 Merge pull request #1741 from Kelimion/shoco
Add Shoco short string compression.
2022-04-22 18:06:31 +02:00
Jeroen van Rijn b022167df1 Remove unused fmt. 2022-04-22 17:56:34 +02:00
Jeroen van Rijn ac9a358c65 [shoco] Replace 2D slices in model with 1D slices. 2022-04-22 17:52:38 +02:00
Jeroen van Rijn e799476f90 [compress/shoco] Add short string compressor. 2022-04-22 16:55:47 +02:00
Jeroen van Rijn b4f8efcbe6 Merge pull request #1739 from ftphikari/master
strings: add levenshtein_distance procedure
2022-04-21 20:31:11 +02:00
hikari f026753692 strings: levenshtein_distance: remove do 2022-04-21 21:19:43 +03:00
hikari 71b1cce517 strings: levenshtein_distance: 64 is actually faster than 256 2022-04-21 21:19:11 +03:00
hikari d8f0da164b strings: levenshtein_distance: improve potential caching 2022-04-21 21:15:11 +03:00
hikari 591732f347 strings: levenshtein_distance: remove costs calculation for default array 2022-04-21 20:58:50 +03:00
hikari eee97f7f62 strings: add levenshtein_distance procedure 2022-04-21 20:49:32 +03:00
Jeroen van Rijn 3dd9da1b66 Merge pull request #1733 from ftphikari/master
sys/windows: add some procedures
2022-04-19 20:41:32 +02:00
Jeroen van Rijn e8c0be23f2 Merge pull request #1737 from Kelimion/fix_json_unmarshal
[json/unmarshal] Fix quoted strings.
2022-04-19 20:40:40 +02:00
Jeroen van Rijn a30b9b17b3 [json/unmarshal] Fix quoted strings. 2022-04-19 20:32:22 +02:00
Jeroen van Rijn 29b2c04766 Revert "Fix unmarshal for escaped strings."
This reverts commit 581255bf23.
2022-04-19 20:11:02 +02:00
Jeroen van Rijn d869ba7bcd Merge pull request #1736 from Kelimion/fix_json_unmarshal
Fix unmarshal for escaped strings.
2022-04-19 20:05:04 +02:00
Jeroen van Rijn 581255bf23 Fix unmarshal for escaped strings. 2022-04-19 20:04:38 +02:00
Jeroen van Rijn b51358a01c Merge pull request #1734 from hanabi1224/lru-alloc-fix
[core:container/lru] Avoid unnecessary allocations
2022-04-19 15:04:49 +02:00
Jeroen van Rijn 323e7a2d02 Add JSON unmarshal test. 2022-04-19 15:03:09 +02:00
Jeroen van Rijn 7654afc2db Revert "Update mem.nil_allocator to match the same in runtime"
The change broke JSON unmarshaling.

This reverts commit 4484a3433d.
2022-04-19 15:01:54 +02:00
hanabi1224 ded8342f3f Reduce allocations 2022-04-19 20:46:33 +08:00
ftphikari 240fb9b953 Merge branch 'odin-lang:master' into master 2022-04-19 06:00:30 +03:00
hikari 4997a43763 Merge remote-tracking branch 'origin/master' 2022-04-19 05:59:42 +03:00
hikari aa4eb35671 sys/windows: add some procedures 2022-04-19 05:58:22 +03:00
Jeroen van Rijn d99ba9c073 Merge pull request #1731 from Kelimion/targa
[image/tga] Writer for RGB(A) 8-bit images.
2022-04-18 23:36:45 +02:00
Jeroen van Rijn fdd24f787f [image/tga] Writer for RGB(A) 8-bit images. 2022-04-18 23:28:34 +02:00
WalterPlinge b6abd691f4 Image: Fix implicit enum error 2022-04-18 20:42:50 +01:00
WalterPlinge 8d370fabdd Added initial Netpbm image format support 2022-04-18 20:29:37 +01:00
Jeroen van Rijn df4a0c62ad Delete accidentally added test artefact. 2022-04-18 19:10:53 +02:00
Jeroen van Rijn e3e3309a9b Merge pull request #1728 from Tetralux/more-slice-helpers
Duplicate some basic slice procedures from core:mem into core:slice
2022-04-18 19:05:20 +02:00
Tetralux 7428e52264 Duplicate some basic slice procedures from core:mem into core:slice 2022-04-18 16:56:45 +00:00
Jeroen van Rijn 20b70c3b7b Merge pull request #1727 from hanabi1224/fix-lru
Fix bugs in core:container/lru
2022-04-18 13:39:23 +02:00
hanabi1224 4247ba67ed Fix bugs in core:container/lru 2022-04-18 15:24:54 +08:00
Jeroen van Rijn e738e93da0 Merge pull request #1723 from ftphikari/master
sys/windows: add timeEndPeriod
2022-04-17 18:27:07 +02:00
hikari b78f3a8069 sys/windows: add timeEndPeriod 2022-04-17 19:17:38 +03:00
Jeroen van Rijn 939973acd7 [QOI] Add to examples/all. 2022-04-17 12:35:34 +02:00
gingerBill ed4cb72b19 Merge pull request #1696 from Despacito696969/master
Fix for `slice_to_components` compilation error
2022-04-16 21:56:13 +01:00
Jeroen van Rijn 70cbffd58b Merge pull request #1722 from Kelimion/varint_streamed
[LEB128] Add byte-at-a-time ILEB decoder.
2022-04-16 18:19:38 +02:00
Jeroen van Rijn 6d0ba8d189 [LEB128] Add byte-at-a-time ILEB decoder. 2022-04-16 18:14:01 +02:00
Jeroen van Rijn b6f3fa6ee1 Merge pull request #1719 from ftphikari/precise_sleep
time: add accurate sleep procedure
2022-04-16 16:52:46 +02:00
Jeroen van Rijn 91037766d2 Update time.odin
Add caveats.
2022-04-16 16:48:08 +02:00
hikari 8bf73950fa time: remove unnecessary yield 2022-04-16 14:36:48 +03:00
hikari 4f4793817c time: fix unix build 2022-04-16 14:35:49 +03:00
hikari 0a0440a6e8 time: yield accurate_sleep instead of relaxing the cpu 2022-04-16 14:08:37 +03:00
hikari b9dc81d808 runtime: update comment description 2022-04-16 13:46:36 +03:00
Jeroen van Rijn 8e7ddccf00 Merge pull request #1717 from ftphikari/master
sys/windows: add procedures and types
2022-04-16 12:38:39 +02:00
Jeroen van Rijn a5773f1657 Merge pull request #1718 from Kelimion/varint_streamed
Add uleb128 byte-at-a-time decoder.
2022-04-16 02:20:07 +02:00
Jeroen van Rijn 44316401c9 Add uleb128 byte-at-a-time decoder. 2022-04-16 02:07:57 +02:00
hikari b05fbaacda time: add accurate sleep procedure 2022-04-16 00:32:17 +03:00
hikari 1b4d5b73ab sys/windows: add some constants 2022-04-15 22:04:34 +03:00
hikari d3fbf36df7 sys/windows: add winmm bindings file 2022-04-15 19:18:22 +03:00
ftphikari de819cff94 Merge branch 'odin-lang:master' into master 2022-04-15 19:16:52 +03:00
hikari cfae39c29d sys/windows: add procedures and types 2022-04-15 19:16:31 +03:00
gingerBill 989641a616 Update Vulkan generation and package 2022-04-15 12:14:12 +01:00
gingerBill fc3f62e3ed Minor rearrangement 2022-04-15 11:50:08 +01:00
gingerBill 6b7c04e046 Improve utilities 2022-04-15 11:33:28 +01:00
gingerBill cfeb16f917 Add more proc groups 2022-04-15 11:20:42 +01:00
gingerBill 9a2d9002e6 Minor fixes and add use of proc groups where better suited 2022-04-15 11:14:59 +01:00
gingerBill ea0b02d9b9 Add Buffer contentsAsSlice and contentsAsType 2022-04-14 16:42:24 +01:00
gingerBill 0d621511e5 Correct signature types 2022-04-14 16:16:53 +01:00
gingerBill e53c858855 Add NS.Block to allow for the creation of block-like lambdas in Odin 2022-04-14 15:47:49 +01:00
gingerBill 8a9f7fc684 Fix #1713 2022-04-14 15:09:03 +01:00
gingerBill 51db46551e Add MetalKit; Add NSApplication NSMenu NSMenuItem; Improve Metal classes 2022-04-14 15:03:47 +01:00
gingerBill 600b79276a Merge pull request #1709 from ap29600/quicksort_fix
Fix tail recursion in `_quick_sort_general`
2022-04-13 11:20:46 +01:00
Andrea Piseri a040be957f Fix tail recursion in _quick_sort_general
The `if` statement should have been a `for` loop, in order to allow recursively
sorting the subarrays with quicksort, and not resort to shell sort after
one step.
2022-04-13 10:55:16 +02:00
Jeroen van Rijn f6fa553572 Merge pull request #1708 from Kelimion/varint_doc
[varint] Clear up doc.odin.
2022-04-13 00:03:58 +02:00
Jeroen van Rijn 8310436350 [varint] Clear up doc.odin. 2022-04-13 00:03:36 +02:00
Jeroen van Rijn f92ffe60e7 Merge pull request #1699 from ftphikari/master
mem: replace size procedures with constants
2022-04-12 20:12:05 +02:00
Jeroen van Rijn de72754d7a Merge pull request #1707 from Kelimion/qoi
[image] Add QOI load/save.
2022-04-12 19:33:11 +02:00
Jeroen van Rijn bf712e9355 [QOI] Add support for RGB images (previously loader always output RGBA).
Also add QOI to CI test suite by roundtripping 8-bit RGB(A) through QOI and checking the hashes match.
2022-04-12 19:23:48 +02:00
Jeroen van Rijn ab9457346d [PNG] Remove debug printf. 2022-04-12 18:26:10 +02:00
Jeroen van Rijn 15b440c4f1 [image] Add QOI load/save.
Additionally:
- Firm up PNG loader with some additional checks.
- Add helper functions to `core:image` to expand grayscale to RGB(A), and so on.

TODO: Possibly replace PNG's post-processing steps with calls to the new helper functions.
2022-04-12 18:14:09 +02:00
gingerBill f2f1330238 Add https://github.com/odin-lang/examples 2022-04-08 10:29:23 +01:00
hikari c4a7739d13 sys/windows: add a couple macros 2022-04-07 19:28:24 +03:00
Mikkel Hjortshøj 8a8b5c753f Update README.md 2022-04-07 16:48:34 +02:00
hikari ad90f416a5 runtime: fix typo 2022-04-07 12:24:53 +03:00
hikari 698fcb7813 mem: replace size procedures with constants 2022-04-06 18:44:43 +03:00
gingerBill 426a6a9528 Update nightly.yml to build the directory 2022-04-05 21:10:24 +01:00
Jeroen van Rijn 50b9c48609 Merge pull request #1697 from Kelimion/build_file
Give build/run/check/test/doc a `-file` flag.
2022-04-05 20:52:28 +02:00
Jeroen van Rijn 767ed21bfe -file for tests\issues. 2022-04-05 20:47:37 +02:00
Jeroen van Rijn bb9165edd2 Add -help to CI tests. 2022-04-05 20:45:00 +02:00
Jeroen van Rijn ad0a413b40 Give build/run/check/test/doc a -file flag.
A package has canonically always been a directory, but odin allowing you to build a single-file package confused newcomers who didn't understand why they could then not access variables and procedures from another file in the same directory.

This change disallows building single-file packages by default, requiring the `-file` flag to acknowledge you understand the nuance.

`-help` for these commands also clarifies the difference.

```
W:\Odin>odin build -help
odin is a tool for managing Odin source code
Usage:
        odin build [arguments]

        build   Compile directory of .odin files as an executable.
                One must contain the program's entry point, all must be in the same package.
                Use `-file` to build a single file instead.
                Examples:
                        odin build .                    # Build package in current directory
                        odin build <dir>                # Build package in <dir>
                        odin build filename.odin -file  # Build single-file package, must contain entry point.

        Flags

        -file
                Tells `odin build` to treat the given file as a self-contained package.
                This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.
```

```
W:\Odin>odin run examples\demo\demo.odin
ERROR: `odin run` takes a package as its first argument.
Did you mean `odin run examples\demo\demo.odin -file`?
The `-file` flag tells it to treat a file as a self-contained package.
```
2022-04-05 20:26:18 +02:00
Despacito696969 7f6c6945ae Fix for slice_to_components
Using `slice_to_components` wouldn't compile because `s.data` is type of `rawptr` and return type is `^T`
2022-04-05 20:17:47 +02:00
gingerBill ca549939f3 Update README.md 2022-04-05 13:33:25 +01:00
gingerBill cdb003bf23 Add Packages and Nightly Builds to README.md 2022-04-05 13:32:06 +01:00
gingerBill a4d2ff05a9 Merge pull request #1688 from bkrypt/fix_file_windows_open_create_append_order
os/file_windows: Fix "create or append" file open behavior
2022-04-05 12:29:20 +01:00
gingerBill 48012ec73c Merge pull request #1679 from Tetralux/fix-std-handle
Have get_std_handle() no longer make the handles uninheritable
2022-04-05 12:15:14 +01:00
Jeroen van Rijn e7dc00b758 Merge pull request #1695 from ftphikari/master
sys/windows: add Dwmapi.lib binding
2022-04-05 13:10:52 +02:00
hikari ef1fbbbce6 Merge branch 'master' of github.com:ftphikari/Odin 2022-04-05 14:04:03 +03:00
hikari 2a59aebe5b sys/windows: add Dwmapi.lib binding 2022-04-05 14:03:29 +03:00
gingerBill 59025b75ba Merge branch 'master' of https://github.com/odin-lang/Odin 2022-04-04 17:04:12 +01:00
gingerBill 2289b7a33d Remove #caller_location from certain calls in core:container/small_array 2022-04-04 17:04:05 +01:00
Jeroen van Rijn 79ec172797 Merge pull request #1694 from Kelimion/define_help
Add extra help line for define/config.
2022-04-03 21:11:19 +02:00
Jeroen van Rijn 2e6ad2a711 Add extra help line for define/config. 2022-04-03 21:06:06 +02:00
Jeroen van Rijn 6be05f315d Merge pull request #1693 from Skytrias/skytrias-strings-documentation-rest
documentation for the rest of the strings library
2022-04-03 19:54:19 +02:00
Michael Kutowski b5aa50aaa4 documentation for the rest of the strings library 2022-04-03 19:37:54 +02:00
Jeroen van Rijn ab91fa6ad5 Merge pull request #1692 from Kelimion/easy_font
[vendor:easy_font] API improvements.
2022-04-03 19:08:18 +02:00
Jeroen van Rijn 376327c87b [vendor:easy_font] API improvements.
Add `print(x, y, text, color, quad_buffer)` version that takes `[]quad`.
		(Same internal memory layout as []u8 API, but more convenient for the caller.)
Add optional `scale := f32(1.0)` param to `print` to embiggen the glyph quads.

```odin
	// Example for use with vendor:raylib

	quads: [999]easy_font.Quad = ---

	color := rl.GREEN
	c     := transmute(easy_font.Color)color
	num_quads := easy_font.print(10, 60, TEXT, c, quads[:])

	for q in quads[:num_quads] {
		tl    := q.tl.v
		br    := q.br.v
		color  = transmute(rl.Color)q.tl.c

		r := rl.Rectangle{x = tl.x, y = tl.y, width = br.x - tl.x, height = br.y - tl.y}

		// Yes, we could just use the `color` from above, but this shows how to get it back from the vertex.
		// And in practice this code will likely not live as close to the `easy_font` call.
		rl.DrawRectangleRec(r, color)
	}
```
2022-04-03 18:53:27 +02:00
Jeroen van Rijn f8f91e52e0 Merge pull request #1691 from eisbehr/stb_easy_font_fix
Fixes for stb_easy_font
2022-04-03 15:30:52 +02:00
Florian Behr f4daf46ff4 Fixes for stb_easy_font 2022-04-03 15:18:01 +02:00
bkrypt e80bee6867 Change order of O_CREATE & O_APPEND checks 2022-04-02 21:55:01 +02:00
gingerBill d10d54710c Merge pull request #1686 from Kelimion/compile-time-assert
Allow optional message for `#assert`.
2022-04-02 15:02:46 +01:00
gingerBill 1ec997461d Add extra checks to atomic intrinsics 2022-04-02 15:00:28 +01:00
gingerBill ec5fc10988 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-04-02 14:38:51 +01:00
gingerBill a232c0888c intrinsics.atomic_type_is_lock_free 2022-04-02 14:38:42 +01:00
Jeroen van Rijn cb5a6b531a Allow optional message for #assert. 2022-04-02 15:31:50 +02:00
Jeroen van Rijn c930a3b4c8 Merge pull request #1685 from ftphikari/master
sys/windows: add a couple of procedures and types
2022-04-02 12:55:51 +02:00
hikari 4c14e92952 sys/windows: add several procedures and macros 2022-04-02 08:23:12 +03:00
hikari 850d4a1e1b sys/windows: add a couple of procedures and types 2022-04-02 07:38:11 +03:00
Jeroen van Rijn dc012ed6dd Merge pull request #1682 from ftphikari/master
sys/windows: add intrinsics.constant_utf16_cstring
2022-04-02 03:27:58 +02:00
Jeroen van Rijn c21c993646 [strings] fix. 2022-04-02 01:54:35 +02:00
gingerBill c3a292a8c7 Remove hms2019 files 2022-04-02 00:36:26 +01:00
Jeroen van Rijn 4044a577cc Merge pull request #1683 from Kelimion/big_nails
[math/big] Tell Python test runner how many nails we use.
2022-04-01 16:33:30 +02:00
Jeroen van Rijn 581d53b96b [math/big] Tell Python test runner how many nails we use.
`_DIGIT_NAILS` is defined as 4, meaning that we use 60 out of every 64 bits.
We can use as few as 1 nail, using 63 bits out of every 64, and all tests will still pass.

However, it needs more testing to see if that's a worthwhile change to make.

For the tests to work properly when changing the nails, Python needs to know about it as well.

In addition, compile the big math code with `-o:speed` going forward.
2022-04-01 16:24:27 +02:00
gingerBill 2bc89260f1 Add explicit memory ordering for the internal Sema implementation 2022-04-01 15:08:58 +01:00
gingerBill c78b83f142 Fix _Sema 2022-04-01 14:51:51 +01:00
hikari e28525e28c sys/windows: fix some procedure definitions and types 2022-04-01 07:28:18 +03:00
hikari 73f9d12d47 sys/windows: add various procedures 2022-04-01 06:22:27 +03:00
hikari b21cf05d44 sys/windows: move L into util.odin 2022-04-01 02:25:10 +03:00
hikari 107bede9fd sys/windows: fix building error 2022-04-01 02:23:44 +03:00
hikari 75cbb09744 sys/windows: add intrinsics.constant_utf16_cstring 2022-04-01 02:11:41 +03:00
Jeroen van Rijn 76cf667a29 Merge pull request #1681 from colrdavidson/fix-nightly
only install the right version of llvm
2022-03-31 22:47:37 +02:00
Colin Davidson 78ee97ec74 only install the right version of llvm 2022-03-31 13:40:28 -07:00
Tetralux c686133172 Have get_std_handle() no longer make the handles uninheritable
This caused all handles returned by GetStdHandle() to also not be inheritable,
which prevents you from handing them to child processes that you might create.

This fixes that.
2022-03-31 17:03:12 +00:00
gingerBill bfcd7a35bf Merge pull request #1621 from colrdavidson/build_freebsd
Core out Makefile, add freebsd building
2022-03-31 16:25:37 +01:00
gingerBill 4484a3433d Update mem.nil_allocator to match the same in runtime 2022-03-31 15:03:56 +01:00
gingerBill 0c4f905d82 Merge pull request #1673 from odin-lang/new-sync
Brand New `package sync` and Atomics Intrinsics
2022-03-31 14:06:00 +01:00
gingerBill 77de7ebde5 Remove code deduplication 2022-03-31 13:26:10 +01:00
gingerBill 2ec3fa93b4 Remove pthreads dependency 2022-03-31 13:10:15 +01:00
gingerBill 9f2d710c35 Change intrinsics.Atomic_Memory_Order fields to use Ada_Case rather than snake_case 2022-03-31 12:57:24 +01:00
gingerBill 22b961ea53 Update Thread Pool in core:thread
Thanks to the work of eisbehr
2022-03-31 11:55:46 +01:00
Jeroen van Rijn 9ea45d35db [ease] Fix flux_stop. 2022-03-31 12:53:04 +02:00
gingerBill 06e8476efc Correct ordering in auto_reset_event_signal 2022-03-31 10:55:18 +01:00
gingerBill 94dbac9a64 Disable thread pool in demo 2022-03-31 01:13:43 +01:00
gingerBill 97a183f412 Clean up thread_windows.odin 2022-03-31 01:13:29 +01:00
gingerBill b2f5b73532 Rename package name to sync 2022-03-31 01:05:50 +01:00
gingerBill 1eac3482a6 Add checks for memory ordering on fences 2022-03-31 01:01:51 +01:00
gingerBill 6636376a81 Correct weak handling 2022-03-31 00:58:01 +01:00
gingerBill ed6bf28004 Update the intrinsics for documentation on atomics 2022-03-31 00:53:34 +01:00
gingerBill 6bc0c611ab Enforce success failure pairings of compare_exchange_*_explicit at compile time 2022-03-31 00:49:53 +01:00
gingerBill ba1930eb01 Update core to use new atomic intrinsics 2022-03-31 00:22:54 +01:00
gingerBill 203382461b Replace the atomic intrinsics
Matching C11 in style
2022-03-31 00:14:49 +01:00
gingerBill 4eb4ae6305 Replace sync with sync2 2022-03-30 17:42:44 +01:00
gingerBill 72ae061769 Add intrinsics.wasm_memory_grow intrinsics.wasm_memory_size 2022-03-30 17:29:37 +01:00
gingerBill 46161f7e19 threading_example allow on Darwin 2022-03-30 16:28:16 +01:00
gingerBill 0c55596f0f Merge pull request #1612 from graphitemaster/fix_thread_data_races
fix thread data races
2022-03-30 16:26:37 +01:00
gingerBill 5f3bfa66c5 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-03-30 16:15:54 +01:00
gingerBill 561b725b0e Improve spin lock for atomic_mutex_lock 2022-03-30 16:15:48 +01:00
gingerBill 3a4630e6b4 Correct atomic_cxchg_* atomic_cxchgweak_* intrinsics behaviour to monotonic on failure for acq, rel, and acqrel 2022-03-30 16:15:23 +01:00
gingerBill abf0fd7efc Merge pull request #1671 from colrdavidson/add_nocrt
Make no crt work on Linux
2022-03-30 12:58:12 +01:00
Colin Davidson a632db3618 Make no crt work on Linux 2022-03-30 04:45:22 -07:00
Jeroen van Rijn a3c81374be Merge pull request #1670 from ftphikari/master
sys/windows: add WM_SYSCOMMAND related constants
2022-03-29 22:11:16 +02:00
hikari 6a3ec5eb36 sys/windows: add WM_SYSCOMMAND related constants 2022-03-29 22:59:45 +03:00
Jeroen van Rijn 740ba6ad47 Merge pull request #1669 from Kelimion/fix_glob_leak
[windows] Fix leak in `glob`.
2022-03-29 16:27:27 +02:00
Jeroen van Rijn df32b5b46c [windows] Fix leak in glob. 2022-03-29 16:13:17 +02:00
Jeroen van Rijn 085fa199ea Merge pull request #1668 from ftphikari/master
sys/windows: add SetTimer() and KillTimer() procedures
2022-03-29 10:09:49 +02:00
hikari 412c9a99d5 sys/windows: add SetTimer() and KillTimer() procedures 2022-03-29 08:56:05 +03:00
Jeroen van Rijn 6e701ef36d Merge pull request #1666 from Kelimion/improve_string_cut
[strings] Improve `cut`, add tests for it.
2022-03-27 22:19:24 +02:00
Jeroen van Rijn 24c48d22bc [strings] Improve cut, add tests for it. 2022-03-27 22:13:26 +02:00
Jeroen van Rijn 3cb8bb6672 Merge pull request #1665 from Kelimion/flux_fixups
[ease] Flux fixups.
2022-03-27 16:55:42 +02:00
Jeroen van Rijn b1c2c0ea7a [ease] Flux fixups. 2022-03-27 16:49:22 +02:00
Jeroen van Rijn 2c498c132e Merge pull request #1663 from Skytrias/skytrias-math-ease
add math easing package
2022-03-27 16:39:25 +02:00
Michael Kutowski 880d330cca update delay to use deltatime, add time left 2022-03-27 16:34:00 +02:00
Jeroen van Rijn a2a503847a Merge pull request #1664 from Skytrias/skytrias-strings-documentation
add string documentation & examples, fix & cleanup string_multi
2022-03-27 13:59:33 +02:00
Michael Kutowski 58f4d533b7 add string documentation & examples, fix & cleanup string_multi 2022-03-27 11:39:17 +02:00
Michael Kutowski d2ff6f424d add math easing package 2022-03-27 11:32:46 +02:00
Jeroen van Rijn 92f985abd5 Merge pull request #1662 from ftphikari/master
sys/windows: add GetSystemMetrics
2022-03-27 03:23:12 +02:00
hikari 3ce17607c6 sys/windows: add AdjustWindowRect and GetWindowRect 2022-03-27 04:17:07 +03:00
hikari 76277f83c1 sys/windows: add GetSystemMetrics 2022-03-27 02:23:40 +02:00
Jeroen van Rijn 2b7529977e Merge pull request #1661 from ftphikari/master
sys/windows: add ClientToScreen
2022-03-27 00:54:44 +01:00
hikari f4125d2d88 sys/windows: add ClientToScreen 2022-03-27 01:42:46 +02:00
Jeroen van Rijn 87e50e5e4d Merge pull request #1660 from Kelimion/hwnd_fix
HWND_TOPMOST, HWND_NOTOPMOST constants
2022-03-26 19:46:28 +01:00
Jeroen van Rijn 86a1c34c3a HWND_TOPMOST, HWND_NOTOPMOST constants 2022-03-26 19:33:53 +01:00
Jeroen van Rijn 3f3cc342b4 Update strings.odin
Fix from Walter.
2022-03-26 18:38:10 +01:00
Jeroen van Rijn 3bf820cf99 Merge pull request #1658 from gitlost/odin_run_unix_exit_code_WEXITSTATUS
Use `WIFEXITED()` and `WEXITSTATUS()` on Unix `system()` exit code
2022-03-26 17:41:41 +01:00
Jeroen van Rijn f2b4087d80 Merge pull request #1656 from ftphikari/master
sys/windows: fix gdi32 raw pointer types
2022-03-26 17:40:00 +01:00
Jeroen van Rijn 3b6d72bb94 Merge pull request #1659 from WalterPlinge/field-iterator
Add fields_iterator procedure
2022-03-25 21:55:43 +01:00
WalterPlinge 9080fa4a9d Update fields_iterator comment
Added ticks for identifiers
2022-03-25 20:51:04 +00:00
WalterPlinge 5616ff9a40 Add fields_iterator proc
Adds a `fields_iterator` proc to `core:strings`
2022-03-25 20:03:39 +00:00
hikari 73b81184fa sys/windows: add MessageBox procedures 2022-03-25 20:53:17 +02:00
hikari f8d3f86d8b sys/windows: fix build 2022-03-25 16:17:53 +02:00
hikari 2f9a410a45 sys/windows: add SetWindowPos() 2022-03-25 16:09:16 +02:00
gitlost 8661457512 Use WIFEXITED() and WEXITSTATUS() on Unix system() exit code
(ensures Odin run returns correct exit code of built executable)
Adds test "tests/core/os/test_core_os_exit.odin" (Unix only)
2022-03-24 19:31:46 +00:00
hikari 5d7b92d391 sys/windows: add mouse states masks 2022-03-24 18:40:23 +02:00
hikari 1d8bc3e917 sys/windows: fix gdi32 raw pointer types 2022-03-24 17:32:11 +02:00
gingerBill a2ad16b609 Merge pull request #1655 from ftphikari/master
sys/windows: add basic Gdi32.lib support
2022-03-24 15:28:24 +00:00
hikari a3b1ac3133 sys/windows: add basic Gdi32.lib support 2022-03-24 17:27:05 +02:00
gingerBill e7b96cf286 Merge pull request #1654 from ftphikari/master
sys/windows: add GetKeyState functions
2022-03-24 14:19:29 +00:00
hikari 01181517dc sys/windows: add GetKeyState functions 2022-03-24 16:04:27 +02:00
gingerBill f702c782f1 Make constant string backing structures use PrivateLinkage compared to InternalLinkage 2022-03-24 12:18:17 +00:00
gingerBill 7203560b06 Fix test 2022-03-24 12:15:03 +00:00
gingerBill 1baeb9406f Utilize union #shared_nil in more places 2022-03-24 12:11:31 +00:00
gingerBill 17e36bd5e1 Utilize union #shared_nil to core:image Error 2022-03-24 12:06:18 +00:00
gingerBill b6b3377786 Remove unneeded semicolons 2022-03-24 12:02:50 +00:00
gingerBill 13cb894b30 Update core:odin for union #shared_nil 2022-03-24 12:00:27 +00:00
gingerBill 3f935bea25 union #shared_nil
This adds a feature to `union` which requires all the variants to have a `nil` value and on assign to the union, checks whether that value is `nil` or not. If the value is `nil`, the union will be `nil` (thus sharing the `nil` value)
2022-03-24 11:55:03 +00:00
gingerBill 3e66eec735 Merge pull request #1653 from ftphikari/master
sys/windows: add virtual keycodes and a couple of constants
2022-03-24 11:29:28 +00:00
gingerBill 277e0ac124 Merge pull request #1651 from gitlost/filepath.split_list_trailing_separator_#1537
Fix issue #1537 "filepath.split_list requires a trailing separator to work"
2022-03-24 11:29:18 +00:00
hikari 2ccfaa7d4e sys/windows: add virtual keycodes 2022-03-23 23:39:26 +02:00
hikari 4bd5de34ea sys/windows: add several of constants 2022-03-23 23:39:09 +02:00
gitlost 374e71e9b0 Fix issue #1537 "filepath.split_list requires a trailing separator"
Does `make()` with `count + 1` and appends final component (note a
  trailing separator will now result in an empty final component)
Adds test "tests/core/path/filepath/test_core_filepath.odin"
2022-03-23 17:44:35 +00:00
gingerBill 07bb93bb5d Merge pull request #1650 from ftphikari/master
sys/windows: fixed calling conventions, added several bindings
2022-03-23 16:27:50 +00:00
hikari b9efd09d17 sys/windows: fixed calling conventions, added several bindings 2022-03-23 17:37:38 +02:00
gingerBill 507b718cb3 Merge pull request #1646 from weshardee/master
Add foreign imports for Darwin to vendor:stb
2022-03-23 15:11:13 +00:00
gingerBill 82f9cbecf8 Merge pull request #1649 from gitlost/maps_with_procedure_values_#829
Fix issue #829 "Compiler crashes when declaring maps with procedure"
2022-03-23 15:10:58 +00:00
gingerBill a8ac59a6e7 Merge pull request #1642 from themole/master
Add user32.odin with most basic procedures to core:sys/windows
2022-03-23 15:03:29 +00:00
Holger Lindner 3d389ee028 sys/windows: Add icon resource constants 2022-03-23 15:02:01 +01:00
gitlost 10c5825715 Fix issue #829 "Compiler crashes when declaring maps with procedure"
Inits `o->value` in `check_expr_base_internal()` so doesn't accidentally
  use last (the proc lit was being set to that of previous string)
Adds test to "tests/issues" and changes CI to use new "run" shells
2022-03-23 12:56:37 +00:00
Wes Hardee f89ebce807 Add foreign imports for Darwin to vendor:stb 2022-03-22 15:55:37 -05:00
Holger Lindner 64601ac439 Merge remote-tracking branch 'origin/master' 2022-03-22 17:24:40 +01:00
Holger Lindner edce27812f Nixify line endings 2022-03-22 16:41:07 +01:00
Holger Lindner 193822b45d Merge remote-tracking branch 'ftphikari/master' 2022-03-22 16:36:50 +01:00
Holger Lindner 43640a8b59 Add SendMessageA/W to sys/windows/user32.odin 2022-03-22 16:23:38 +01:00
gingerBill 0446d9721b Merge pull request #1626 from gitlost/hxa_fixes
Fix some core:encoding/hxa stuff (error handling, header, max -> min)
2022-03-22 15:21:40 +00:00
Holger Lindner bae13b6387 Fix incorrect type for wndproc callback procedure 2022-03-21 20:06:50 +01:00
hikari e48c0eee74 sys/windows: added rudimentary User32.lib bindings 2022-03-21 18:44:31 +02:00
Holger Lindner 47e9857eb7 Add user32.odin with most basic procedures to core:sys/windows 2022-03-21 17:20:43 +01:00
gingerBill 559fcfa291 Merge pull request #1632 from gitlost/const_in_if_#1592
Fix issue #1592 "LLVM code gen error when using a constant in an if"
2022-03-21 11:16:59 +00:00
gingerBill 84cee5d9d5 Merge pull request #1640 from Lperlind/split-iterator-byte
Add split_iterator_byte
2022-03-21 10:49:21 +00:00
Lucas Perlind 6d354524e2 * Add split_by_byte_iterator. It functions exactly like split_iterator but takes in a byte seperator rather than a string seperator.
The intention is to provide a faster split parsing if the seperator is known to be byte size.
2022-03-21 21:39:30 +11:00
gingerBill ae6441182d Add core:unicode/utf8/utf8string to examples/all 2022-03-18 23:32:37 +00:00
gingerBill a68f0b2d72 Improve procedure group selection based on the minimum number of arguments 2022-03-18 22:18:12 +00:00
gitlost fdbbf24271 Fix issue #1592 "LLVM code gen error when using a constant in an if"
Changes lb_build_if_stmt() to return null lbValue if condition is
  cmpAnd, cmpOr or non-const neg and check in lb_build_if_stmt()
  to avoid short circuiting if that's the case
Adds test to "tests/issues" and adds step in CI to check this dir
2022-03-18 13:57:22 +00:00
Jeroen van Rijn df233f72a9 Merge pull request #1629 from Lperlind/more-window-bindings
Add unregister_class_a and unregister_class_w for windows bindings
2022-03-18 13:29:53 +01:00
gingerBill bff5a67f79 Merge pull request #1631 from Tetralux/fix
Remove incorrect #packed from sys/windows.STARTUPINFO
2022-03-18 11:52:05 +00:00
Tetralux 4f9df50dc1 Remove incorrect #packed from sys/windows.STARTUPINFO 2022-03-18 11:42:25 +00:00
Lucas Perlind 34187424b8 Add unregister_class_a and unregister_class_w for windows bindings 2022-03-18 19:35:36 +11:00
Jeroen van Rijn 50503cb405 Merge pull request #1628 from StanislavNikolov/fix-math-cumsum-inplace
Fix #1627: Remove wrong return type in cumsum_inplace
2022-03-17 03:35:17 +01:00
Stanislav Ch. Nikolov 5e04ddd653 Fix #1627: Remove wrong return type in cumsum_inplace 2022-03-17 04:20:39 +02:00
gitlost 4f5203e661 Fix some core:encoding/hxa stuff (error handling, header, max -> min)
Also add missing f16 case to core:reflect as_u64 & as_f64
Add tests for above & add previous tests missing from test/core/build.bat
2022-03-16 19:12:00 +00:00
gingerBill d9ca4eb4d6 Add nil check on ast.walk 2022-03-16 11:59:28 +00:00
Jeroen van Rijn 5534c031b3 Merge pull request #1624 from Kelimion/insert_at_fix
[runtime] fix `insert_at` procedure group.
2022-03-15 19:44:05 +01:00
Jeroen van Rijn 19dc84e300 Reinstate NBC. 2022-03-15 19:37:04 +01:00
Jeroen van Rijn a932168f50 [runtime] fix insert_at procedure group. 2022-03-15 19:35:00 +01:00
gingerBill 1d147ba993 Fix typo 2022-03-14 12:44:35 +00:00
gingerBill 6ea9ba16e7 Fix #1610 2022-03-14 12:38:56 +00:00
gingerBill 286549693e Fix #1609 2022-03-14 12:28:28 +00:00
Colin Davidson 34727f99e3 oops, fix report 2022-03-14 05:27:08 -07:00
gingerBill ffe6d81ecd Remove comments 2022-03-14 12:24:10 +00:00
Colin Davidson 8605833781 core out Makefile, add freebsd building 2022-03-14 05:23:48 -07:00
gingerBill 4474144c24 Merge pull request #1505 from jasonKercher/fix_odin_test
fix `odin test`
2022-03-14 12:09:39 +00:00
Jeroen van Rijn ef3f448861 Remove accidentally committed test binary. 2022-03-14 13:06:50 +01:00
gingerBill a882260db6 Merge pull request #1605 from colrdavidson/linux_build
Make llvm-config build more general for linux
2022-03-14 11:39:03 +00:00
gingerBill 633157f4f8 Merge pull request #1613 from semarie/linux_arm64
fix Linux arm64 support
2022-03-14 11:37:45 +00:00
gingerBill 9fa69c3d3b Merge pull request #1599 from gitlost/fract_trunc_classify_#1574
Fix for trunc_f16/32/64 (#1574)
2022-03-14 11:37:11 +00:00
gingerBill 743a461aa9 Merge pull request #1614 from semarie/openbsd-fpos_t
use distinct type for fpos_t on OpenBSD
2022-03-14 11:11:29 +00:00
gingerBill fc0291d745 Merge pull request #1526 from odin-lang/freestanding_amd64
Freestanding target for amd64
2022-03-14 11:09:52 +00:00
gingerBill 77eaf8e1e4 Merge pull request #1617 from semarie/freebsd
freebsd_amd64 support
2022-03-14 11:04:58 +00:00
gingerBill a7adb2fb6e Merge branch 'master' into freestanding_amd64 2022-03-14 11:02:59 +00:00
Sébastien Marie 036900da51 fix mode_t on darwin
- fix mkdir() prototype (mode_t is u16)
- remove explicit cast
2022-03-13 12:41:03 +00:00
Sébastien Marie ed4c9335db enable freebsd_amd64 inside CI 2022-03-13 11:43:36 +00:00
Sébastien Marie ca67cf032c freebsd_amd64 support 2022-03-13 11:42:42 +00:00
gingerBill f907516cbd #Fix 1615 Replace llvm.readcyclecounter with cntvct_el0 on arm64 2022-03-12 10:48:31 +00:00
gingerBill c12c7d5370 Remove tag 2022-03-12 10:47:52 +00:00
Sébastien Marie f7c8b40ea2 use distinct type for fpos_t on OpenBSD 2022-03-12 09:40:55 +00:00
Sébastien Marie 15f9795ab0 enable linux_arm64 check in CI 2022-03-12 09:21:46 +00:00
Sébastien Marie 8982ae34e3 fix linux_arm64
- SYS_fork doesn't exist, uses SYS_clone
- properly cast AT_FDCWD to uintptr
2022-03-12 09:19:52 +00:00
gingerBill e6d3e893a5 Merge pull request #1602 from hoanga/freebsd-build-support
update to build for freebsd
2022-03-12 08:45:53 +00:00
Dale Weiler 3da8fa9b27 can use sync.guard here 2022-03-11 08:41:03 -05:00
Dale Weiler 32ba5e7ad2 formatting 2022-03-11 08:36:04 -05:00
Dale Weiler 52df80dccd fix for mac & use atomic store on write side to avoid race 2022-03-11 08:35:23 -05:00
Dale Weiler 7f845bb165 fix for spurious wakeups 2022-03-11 08:30:03 -05:00
Dale Weiler 0e6de5673b fix thread data races 2022-03-11 08:06:23 -05:00
Jeroen van Rijn 7a7b87181d [examples] Add core:encoding/varint to examples/all. 2022-03-11 11:09:58 +01:00
gingerBill c6dc517004 Correct: murmur32 2022-03-11 08:52:16 +00:00
Jason Kercher d2bc41a2df Merge remote-tracking branch 'upstream/master' into fix_odin_test 2022-03-09 17:17:40 -05:00
gitlost 7dbcaf792d Merge branch 'master' into fract_trunc_classify_#1574
Resolve conflicts with [9848e88] & sameify Makefile & tests/common/common.odin
2022-03-09 16:09:04 +00:00
Colin Davidson 2652c2d7a5 normalize version parser 2022-03-09 07:42:38 -08:00
Colin Davidson a2250a5d49 lower minimum llvm version 2022-03-09 07:24:49 -08:00
Colin Davidson 7f8a9587e0 more build tweaks? 2022-03-09 07:22:48 -08:00
Colin Davidson 1306c53fb1 more build tweaks? 2022-03-09 07:21:19 -08:00
Colin Davidson 3bd1ac4c82 test adjusting apt arg order 2022-03-09 07:18:41 -08:00
gingerBill dc8d28c383 Fix #1607 2022-03-09 15:15:30 +00:00
Colin Davidson 7adaa4dc2b refix make, adjust build for CI weirdness 2022-03-09 07:15:08 -08:00
gingerBill 6d1a91f5b3 Fix typo 2022-03-09 15:11:38 +00:00
gingerBill 17eebf338c Fix #1606 (Call runtime._cleanup_runtime_contextless() for os.exit) 2022-03-09 15:05:51 +00:00
Colin Davidson c543ecd64c Try to find llvm-config-11 on goofy misconfigured CI box 2022-03-09 06:57:59 -08:00
Colin Davidson 34a9f55f37 Update ci to use build script 2022-03-09 06:52:22 -08:00
Colin Davidson 9aea990184 clean up osx semver handling in build 2022-03-09 06:49:52 -08:00
Colin Davidson d5b0632e4f add handling for too many args 2022-03-09 06:27:52 -08:00
Colin Davidson db169a4334 Cleanup build mode selection 2022-03-09 06:26:25 -08:00
Colin Davidson f5cc8bd7bf only build odin for report when necessary 2022-03-09 06:14:30 -08:00
Colin Davidson 005d52cab7 more spacing issues 2022-03-09 06:08:48 -08:00
Colin Davidson d1477bcfa7 Fix wonky copied space issues 2022-03-09 06:07:19 -08:00
Colin Davidson 3092fb2ff3 Add initial cut of build script 2022-03-09 06:01:40 -08:00
Colin Davidson 5eebdebec8 Make llvm-config build more general for linux 2022-03-09 05:09:39 -08:00
gingerBill 8e4d6b3e5d Fix typo 2022-03-09 11:24:36 +00:00
gingerBill ea9c2fed57 Update .gitignore 2022-03-09 10:52:37 +00:00
gingerBill ba412fd87b Fix typo 2022-03-09 09:36:21 +00:00
Al Hoang 0278ac85a0 update to build for FreeBSD 2022-03-08 23:48:25 -06:00
gingerBill ff60b752bd Replace #if with if where possible 2022-03-08 22:35:10 +00:00
gingerBill 9848e883c7 Merge pull request #1598 from Kelimion/varint
Add `core:encoding/varint` with LEB128 encoding, decoding and tests.
2022-03-08 20:46:31 +00:00
Jeroen van Rijn 64705ddd1d [varint] Add doc.odin 2022-03-08 20:08:56 +01:00
Jeroen van Rijn 2a41814985 [varint] Tighten max input bounds. 2022-03-08 19:56:42 +01:00
Jeroen van Rijn 26ffec845b [crypto] Remove unused mem import for siphash. 2022-03-08 19:38:36 +01:00
Jeroen van Rijn 52e60526ef tabs. 2022-03-08 19:32:30 +01:00
Jeroen van Rijn 76b10b5f5d [varint] Add additional LEB128 tests. 2022-03-08 19:28:55 +01:00
gitlost b94a7a87fa Fix issue #1574 "fract in linalg/glm is broken" by fixing
trunc_f16/32/64 in "math.odin" (~ typos on expressions)
Fix classify_f16 Inf test (would fail for subnormal 0h0001)
  by changing multiplier 0.5 -> 0.25
Add some useful consts to "math.odin" (INF_F16 etc)
Add comment to "demo.odin" mentioning that -0.0 must be used
  to specify negative zero
2022-03-08 18:06:25 +00:00
gingerBill 2b43387a9d Merge pull request #1597 from odin-lang/nix-linker-flags-improvement
Refactor link flag creation for nix systems
2022-03-08 17:12:28 +00:00
Jeroen van Rijn e76a5d8e12 [varint] Add signed LEB128 encoding. 2022-03-08 18:07:16 +01:00
Jeroen van Rijn 6d7217f37a [varint] Add LEB128 decoding + tests
Also make tests in general less spammy: Don't print [PASS] for each successful test, only report failures and progress.
2022-03-08 15:40:00 +01:00
gingerBill 17dab04422 Refactor link flag creation for nix systems 2022-03-08 11:13:59 +00:00
gingerBill 29e660b16f Add more things to package slice
min_max
any_of(_proc)
none_of(_proc)
all_of(_proc)
count(_proc)
2022-03-08 10:02:40 +00:00
gingerBill 31959b0751 Correct cleanpath_from_handle for os.fstat 2022-03-08 10:01:44 +00:00
gingerBill 8f897de267 Merge pull request #1584 from WalterPlinge/vulkan-proc-loader-functions
update vulkan generator and procedure file
2022-03-07 18:54:26 +00:00
Jeroen van Rijn 2855ff6df3 Merge pull request #1591 from Kelimion/unaligned_load
[intrinsics] Add existing `unaligned_load` and `unaligned_store`.
2022-03-06 14:59:24 +01:00
Jeroen van Rijn deed20dea6 [intrinsics] Add unaligned_store. 2022-03-06 14:53:06 +01:00
Jeroen van Rijn a6c5143993 [intrinsics] Add existing unaligned_load. 2022-03-06 14:46:20 +01:00
Jeroen van Rijn 758d1e2a03 Merge pull request #1589 from Kelimion/fix_bit_array_leak
[bit_array] Really fix the leak.
2022-03-06 12:38:08 +01:00
Jeroen van Rijn ce057ff755 [bit_array] Really fix the leak. 2022-03-06 12:29:17 +01:00
gingerBill ad719e7c3a Merge pull request #1588 from ap29600/master
Fix leak in `core:container/bit_array`
2022-03-06 09:43:12 +00:00
Andrea Piseri bff3426d25 Fix leak in core:container/bit_array
calling `clear` on a `bit_array` no longer leaks the previous
allocation, instead it sets all bits to `false` preserving the same
backing dynamic array.
2022-03-06 10:21:46 +01:00
gingerBill 4315033220 Merge pull request #1585 from kstrb/foreign-import-object
Linux: allow 'foreign import' of object files
2022-03-05 20:29:39 +00:00
kstrb 1cd89b2da3 Linux: allow 'foreign import' of object files 2022-03-05 17:28:34 +01:00
WalterPlinge 7e8b9862b9 update vulkan generator
change procedure file generation
- group procedure types together
- sort groups by procedure names
- overload function `load_proc_addresses`
    - kept original as `custom`
    - added `global`, `instance`, and `device` variants for simpler loading
    - added `device_vtable` variant to support multiple devices
2022-03-04 16:16:31 +00:00
gingerBill 07062324d7 Merge pull request #1575 from jockus/fix_relative_slice_len
Add relative slice to type checks for built in len
2022-03-04 11:48:29 +00:00
gingerBill 2e8f2e6dbc Merge pull request #1476 from odin-lang/odin-ast-changes
Replace `any` with `union` for subtyping in `core:odin/ast`
2022-03-04 10:39:38 +00:00
gingerBill 1abd95094d Add reflect.deref 2022-03-03 23:25:22 +00:00
gingerBill 913d802e33 Fix ast.clone_node 2022-03-03 23:10:38 +00:00
Jeroen van Rijn bee475c38a Merge pull request #1582 from semarie/more-ci
CI: add linux i386, Darwin arm64 and Windows 386
2022-03-03 17:07:40 +01:00
Jeroen van Rijn b4ca99ead9 Merge pull request #1583 from semarie/semi-colons-eof
Semi colons and EOF
2022-03-03 17:06:13 +01:00
Sébastien Marie dfe2c0a600 remove some leftover semi-colons before EOF 2022-03-03 15:57:55 +00:00
Sébastien Marie fad851d80c check for semi-colon before EOF too 2022-03-03 15:57:51 +00:00
Sébastien Marie 832961d539 semi-colons are deprecated in core 2022-03-03 15:36:04 +00:00
Sébastien Marie 499c657ffa rename architecture from 386 to i386 2022-03-03 15:28:18 +00:00
Sébastien Marie 8c6f39a68d CI: add linux i386, Darwin arm64 and Windows 386 2022-03-03 15:08:34 +00:00
gingerBill 09f5713cf8 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-03-03 14:31:45 +00:00
Jeroen van Rijn 26c0c6a525 Merge pull request #1581 from Kelimion/32-bit-fixes
32 bit fixes
2022-03-03 15:26:42 +01:00
Jeroen van Rijn 6d9f84ba03 [tests] Make test runners exit with errorlevel 1 if a test fails. 2022-03-03 15:16:16 +01:00
Jeroen van Rijn 8af08f2153 [compress] 32-bit cleanness. 2022-03-03 15:10:19 +01:00
gingerBill 2944969ca0 Correct clone_node 2022-03-03 14:01:37 +00:00
gingerBill bd1b54e0db Fix #1503 2022-03-03 13:58:22 +00:00
gingerBill fcab5508be Merge branch 'master' into odin-ast-changes 2022-03-03 13:56:34 +00:00
gingerBill 0b05650366 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-03-03 13:54:31 +00:00
gingerBill 96e36c7c39 Minor fix to strconv.unquote_string 2022-03-03 13:54:23 +00:00
gingerBill 16c6dbcbe5 Merge pull request #1579 from semarie/vendors
Vendors libraries portability and examples/all splitting
2022-03-03 12:09:46 +00:00
gingerBill 92a78c83d9 Merge pull request #1571 from SrMordred/patch-4
Fixing bindings
2022-03-03 12:08:17 +00:00
gingerBill 6b2302fa8b Merge pull request #1572 from Lperlind/better-fmt
Improve core:fmt formatting
2022-03-03 12:07:14 +00:00
gingerBill ee28945e09 Update FUNDING.yml 2022-03-03 11:19:12 +00:00
Sébastien Marie 3dcea60f5b vendor: ENet: follow strict-style and remove optional semi-colon 2022-03-03 09:27:10 +00:00
Sébastien Marie f126e05034 stb, miniaudio: use default builtin variables of make for CC and AR 2022-03-03 07:36:47 +00:00
gingerBill 68b74eb7c7 Merge pull request #1577 from zhibog/crypto_rand_windows
Added rand_bytes for Windows in core:crypto
2022-03-02 23:10:31 +00:00
zhibog 3b4199a669 Added rand_bytes for Windows in core:crypto 2022-03-02 21:22:56 +01:00
Sébastien Marie 562901aedf split all_vendor.odin
create 3 files:
- all_vendor.odin : no specific OS
- all_vendor_directx.odin : directx vendor, windows-only
- all_vendor_stb.odin : stb vendor, windows and linux only

stb could technically be used on others OS. but it is shipped upstream as set of c-files without unified library name.
2022-03-02 19:21:22 +00:00
Sébastien Marie 793117ed63 vendor: sdl2: simplify foreign import 2022-03-02 18:50:37 +00:00
Sébastien Marie 5b783d6376 vendor: raylib: simplify foreign import 2022-03-02 18:44:29 +00:00
Sébastien Marie d3f3528d1d vendor: portmidi: simplify foreign import 2022-03-02 18:43:17 +00:00
Sébastien Marie 3145935d6b miniaudio
- simplify foreign
- enable SUPPORT_SNDIO on OpenBSD
- correct ptr type for SUPPORT_PULSEAUDIO (Linux) and SUPPORT_COREAUDIO (Darwin)
2022-03-02 18:35:13 +00:00
Sébastien Marie 25430333ba vendor: glfw: simplify foreign import 2022-03-02 18:25:22 +00:00
Sébastien Marie 2ca2b32dd0 vendor: botan: simplify foreign import 2022-03-02 18:21:43 +00:00
Joakim Hentula a5dde78f08 Add relative slice to type checks for built in len 2022-03-02 16:44:33 +00:00
gingerBill fd415f0b45 Merge pull request #1573 from semarie/openbsd-vendor
Openbsd vendor
2022-03-02 12:56:12 +00:00
Lucas Perlind 507722954c Improve core:fmt formatting
* Strings will respect widths smaller than the string's length
* Strings are right justified by default like integers
* Strings accept '-' flag to be left justified
* Booleans will be formatted like strings
* Enums will be formatted like strings
2022-03-02 16:22:16 +11:00
Patric Dexheimer 524d23d45d Update raylib.odin 2022-03-01 16:55:34 -03:00
Patric Dexheimer e9ee6f5291 Fixing bindings
https://github.com/raysan5/raylib/blob/master/src/raylib.h#L1179
2022-03-01 16:00:18 -03:00
gingerBill 7e5342f41f Use contextless where possible 2022-03-01 15:52:14 +00:00
gingerBill 18607e53cb Correct alloc_from_memory_block 2022-03-01 15:38:04 +00:00
gingerBill ed933b3f21 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-03-01 14:49:11 +00:00
gingerBill 49fecbdc5e Improve error message when there is "no field" found for a large anonymous struct 2022-03-01 14:49:05 +00:00
Jeroen van Rijn f971126183 [mem] Add missing \n to tracking allocator example. 2022-03-01 13:51:41 +01:00
gingerBill d4ccb69ccc Check if directory exists with the same target executable name when building a directory 2022-02-28 21:49:19 +00:00
Sébastien Marie 37b4e0de6c sdl2: add openbsd support 2022-02-28 16:17:15 +00:00
Sébastien Marie 737f440c7f glfw: add openbsd support 2022-02-28 16:17:14 +00:00
Sébastien Marie cba3f1e374 ENet: add openbsd support 2022-02-28 16:17:14 +00:00
gingerBill a70dde34da Merge pull request #1565 from semarie/openbsd-pie
openbsd: defaults to PIE executable
2022-02-28 16:11:59 +00:00
gingerBill 410b85b5c7 Disallow @(thread_local) on wasm targets 2022-02-28 15:40:00 +00:00
gingerBill 0ae012ba08 Correct comment 2022-02-28 15:37:15 +00:00
gingerBill fc4eb4152c Correct calling convention for _startup_runtime 2022-02-28 15:35:10 +00:00
gingerBill 4f3b5d8dcb Clean up generate_minimum_dependency_set code 2022-02-28 15:29:08 +00:00
Sébastien Marie f76f70c7cf openbsd: defaults to PIE executable
OpenBSD uses PIE code by default to allow the system to load the binary at a random location.

don't pass -no-pie to preserve this behaviour, and build objects with -fPIC (LLVMRelocPIC).
2022-02-28 15:24:22 +00:00
gingerBill 15d783e920 Enforce -no-entry-point on freestanding targets 2022-02-28 15:13:41 +00:00
gingerBill 09e4fff5b1 -target-features:<string>
This just passes a string directly to the LLVM features string
2022-02-28 15:08:50 +00:00
gingerBill 2d89faa17c Add extra checks for -disallow-rtti 2022-02-28 14:35:38 +00:00
gingerBill dd9843aa21 Merge pull request #1557 from semarie/openbsd-support
initial OpenBSD support
2022-02-28 14:23:56 +00:00
gingerBill 882116e358 Only allow -disallow-rtti on freestanding targets 2022-02-28 14:00:44 +00:00
gingerBill f3adbae1ed Merge branch 'freestanding_amd64' of https://github.com/odin-lang/Odin into freestanding_amd64 2022-02-28 13:40:06 +00:00
gingerBill 278e239973 Commit rest of code for -disallow-rtti 2022-02-28 13:40:01 +00:00
gingerBill fda803b46a Commit rest of code for -disable-rtti 2022-02-28 13:39:27 +00:00
gingerBill 01162e08b5 Add -disallow-rtti 2022-02-28 13:35:29 +00:00
gingerBill a7ae197a55 Merge branch 'master' into freestanding_amd64 2022-02-28 13:02:31 +00:00
gingerBill 3c72cb67d3 Remove context.user_data 2022-02-28 13:00:32 +00:00
gingerBill 37bba4c0a6 Reorganize error check procedures 2022-02-28 12:45:19 +00:00
gingerBill ab9d1f99fd Change #c_vararg checking to only disallow odin calling conventions 2022-02-28 12:36:21 +00:00
gingerBill 45124e4d5c Merge branch 'master' into freestanding_amd64 2022-02-28 12:32:51 +00:00
gingerBill 7681c43b14 Show error message when something like this is done test: proc() : {} 2022-02-28 12:12:04 +00:00
gingerBill 7e43cd7d97 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-28 12:06:42 +00:00
gingerBill c223fc1766 Correct debug information for local variables 2022-02-28 12:06:35 +00:00
Sébastien Marie 04297bb680 ci: add check for OpenBSD amd64 2022-02-26 14:18:37 +00:00
Sébastien Marie 553292ffd0 vendor: botan: add OpenBSD support 2022-02-26 08:47:58 +00:00
Sébastien Marie 57862846a2 tests/vendor: pass extra linker flags
on OpenBSD, botan library is third-party and live in /usr/local which isn't a path included by default in linker.
2022-02-26 08:21:46 +00:00
Sébastien Marie 8e270d3a99 openbsd: poor man implementation for getting executable path
it tries to get executable path from argv[0]. it is unreliable and unsecure, but should be fine enough for the considered use-case. it still doesn't address all possible cases.
2022-02-26 08:19:41 +00:00
Sébastien Marie ae5cb09041 internal_odin_root_dir: readlink could fail 2022-02-25 17:59:57 +00:00
gingerBill 093b2288c3 Merge pull request #1320 from mohd-akram/custom-llvm-config
Allow custom LLVM_CONFIG
2022-02-25 15:57:53 +00:00
Mohamed Akram ffe17a471d Allow custom LLVM_CONFIG 2022-02-25 19:40:42 +04:00
gingerBill e9f901b82d Keep -vet happy 2022-02-25 15:30:24 +00:00
gingerBill ed3004f8a0 Correct read_console reading 2022-02-25 15:30:05 +00:00
gingerBill d97df080f9 Revert change 2022-02-25 15:08:02 +00:00
gingerBill 0e5c7e08fc Change < to <= 2022-02-25 14:54:35 +00:00
Sébastien Marie 83523badb7 pass -ldl only on Darwin and Linux 2022-02-25 13:02:12 +00:00
Sébastien Marie 0a90994403 provide a simple gb_file_copy() implementation
permit to not require sendfile(2) syscall for gb_file_copy()
2022-02-25 12:32:34 +00:00
gingerBill 376906e0ae Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-25 12:02:49 +00:00
gingerBill 47c79a2f25 Correct os.read on windows for os.stdin 2022-02-25 12:02:41 +00:00
gingerBill 32988b0363 Correct internals for os.read on windows (read_console) for os.stdin (Fix #1556) 2022-02-25 12:01:53 +00:00
Sébastien Marie 00c138ce9f add RAM information inside report 2022-02-25 09:28:04 +00:00
Sébastien Marie 5676c9e7eb initial OpenBSD support 2022-02-25 08:49:25 +00:00
Jeroen van Rijn 3a469dc13e Merge pull request #1549 from semarie/clone_to_cstring-leak
delete allocated memory with clone_to_cstring
2022-02-24 12:42:15 +01:00
Sébastien Marie d3c70f2206 remove the optional ; in os_freebsd.odin 2022-02-24 11:30:33 +00:00
Sébastien Marie 14f1793b3e use context.temp_allocator instead of general allocation + delete()
where clone_to_cstring is used with foreign code, it is prefered to use `context.temp_allocator` instead of using the general allocator and manually delete the memory after use.
2022-02-24 11:28:42 +00:00
Jeroen van Rijn 8cecb6b9f5 Merge pull request #1548 from colrdavidson/darwin_docs
Add make_directory so darwin can build html docs
2022-02-24 11:51:20 +01:00
Jeroen van Rijn 4a66c3c420 Merge pull request #1546 from zacharycarter/patch-2
adding `is_16_bit_from_memory` to stbi
2022-02-24 11:49:08 +01:00
gingerBill c3c88633a5 Merge pull request #1545 from AquaGeneral/master
Added options to help, and improved wording
2022-02-24 10:15:13 +00:00
Colin Davidson aeaf1199ec Add make_directory so darwin can build html docs 2022-02-24 01:13:51 -08:00
Tail Wag Games d4f62f52db adding is_16_bit_from_memory to stbi 2022-02-24 00:20:15 -06:00
Jesse Stiller 384fb76a1b Added options to help, and improved wording 2022-02-24 12:59:06 +10:00
gingerBill 4a04a32e0a Change target name to freestanding_amd64_sysv 2022-02-23 11:33:28 +00:00
gingerBill 196bd735d4 Replace local @(no_red_zone) with global -disable-red-zone 2022-02-23 11:29:36 +00:00
gingerBill 493bc653b5 Add @(no_red_zone) for procedures 2022-02-23 11:23:27 +00:00
gingerBill 3d209798c9 Add help docs for -reloc-mode:<string> 2022-02-23 11:19:51 +00:00
Jeroen van Rijn dd0d61e97c Merge pull request #1528 from Tetralux/split-docs
Add doc comments to strings.split() and strings.split_n()
2022-02-23 12:13:29 +01:00
gingerBill 4b9324ff76 Merge branch 'master' into freestanding_amd64 2022-02-23 11:03:48 +00:00
gingerBill e81ed9a960 Add "Did you mean" to Objective-C fields 2022-02-22 23:19:49 +00:00
gingerBill 83f7a887b7 Move comment 2022-02-22 23:03:04 +00:00
gingerBill ad2f1ac24e Improve union_tag_size 2022-02-22 23:01:28 +00:00
gingerBill 62d232d798 Correct ExactValue_Pointer 2022-02-22 22:59:00 +00:00
gingerBill 8906a0120c Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-22 22:53:19 +00:00
gingerBill cad753e398 Simplify parse_binary_expr 2022-02-22 22:53:13 +00:00
Jeroen van Rijn fd627dc13b Merge pull request #1535 from zhibog/add-siphash
Added SipHash + tests and fixed remaining semicolons in vendor/botan
2022-02-22 20:34:50 +01:00
zhibog 70e8d97ee1 Fix procedure 2022-02-22 20:13:49 +01:00
zhibog cdecb0ccc3 Fix Odin_OS_Type 2022-02-22 20:10:35 +01:00
zhibog 460b5149af Added missing constants 2022-02-22 20:06:52 +01:00
zhibog b6dc253d8b Add generic procedure for default SipHash 2-4 2022-02-22 20:02:34 +01:00
zhibog e7be9493ba Added SipHash + tests and fixed remaining semicolons in vendor/botan 2022-02-22 19:56:07 +01:00
Jeroen van Rijn ea34f321ed Merge pull request #1533 from odin-lang/bug_report
[report] Fix `odin report` crash if `/usr/lib/os-release` doesn't exist.
2022-02-22 17:14:24 +01:00
Jeroen van Rijn 2b5bc1d558 [report] Fix odin report crash if /usr/lib/os-release doesn't exist. 2022-02-22 17:08:57 +01:00
gingerBill e6a7b85da4 Correct types 2022-02-21 20:49:59 +00:00
gingerBill 6145185478 Add missing return types 2022-02-21 16:04:56 +00:00
Tetralux 2abba6e057 Don't use leading asterisks 2022-02-21 09:51:03 +00:00
Tetralux db5a1b0c78 Add doc comments to strings.split() and strings.split_n() 2022-02-21 09:23:45 +00:00
gingerBill 14cb19c2df Update fmt to record the bytes written in the fmt.Info 2022-02-20 22:31:13 +00:00
gingerBill 46bcd18946 Merge pull request #1519 from colrdavidson/hyperspeed_file_size
Maintain a running count printed, so fprintf returns correct sizes for non-files
2022-02-20 22:16:27 +00:00
gingerBill 3e5c60f746 Add -reloc-mode:<string> 2022-02-20 14:48:12 +00:00
gingerBill 0fa487f468 Add -foreign-error-procedures 2022-02-20 14:27:44 +00:00
gingerBill 1bec9e5331 Add freestanding_amd64_gnu 2022-02-20 14:19:52 +00:00
gingerBill ba61d911da Remove dead code 2022-02-20 13:26:27 +00:00
Jeroen van Rijn 3b69c6b204 Merge pull request #1521 from SrMordred/patch-3
Memory Leak
2022-02-20 11:54:31 +01:00
Patric Dexheimer d7eabf571c Memory Leak
`dir` will leak memory if u use it with allocators that don´t care in freeing the memory at the end ( like arenas or the temp_allocator ) , because `strings.clone` and `strings.concatenate` are not using the passed allocator.
2022-02-20 02:10:34 -03:00
Colin Davidson ddf9c4a65b switch to passing total_size to the io.writers 2022-02-19 16:38:33 -08:00
Colin Davidson b3d797598e fprintf tweaked to avoid calling file_size 2022-02-19 15:51:11 -08:00
gingerBill 31c7945444 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-19 15:45:08 +00:00
gingerBill 276e014d18 Update comment in demo.odin 2022-02-19 15:45:01 +00:00
Jeroen van Rijn 27f206784c Merge pull request #1514 from colrdavidson/fast_file_size
Use the _unix_fstat pointer to avoid 144B copies on fileIO
2022-02-19 12:17:03 +01:00
Colin Davidson 54a6637d38 Use the _unix_fstat pointer to avoid 144B copies on fileIO 2022-02-18 20:50:49 -08:00
gingerBill 23be56af59 Remove prefixes from D3D12 constants 2022-02-18 21:45:20 +00:00
gingerBill 71df46456a Minimize memory usage by having an arena per thread rather than an arena per file 2022-02-18 21:30:25 +00:00
gingerBill cd89d8a3c4 Add better error message for compiler when OOM happens 2022-02-18 16:24:08 +00:00
gingerBill 4c62a32b04 Keep -vet happy 2022-02-18 16:13:52 +00:00
gingerBill 5f8137025d Use try_to_add_package_dependency 2022-02-18 16:12:21 +00:00
gingerBill 1843d52217 Fix typo 2022-02-18 16:07:06 +00:00
gingerBill 454c92dc64 Allow objc intrinsics within odin check and odin docs but disallow for odin build 2022-02-18 16:05:26 +00:00
gingerBill 7e33a86d54 Remove unneeded semicolon 2022-02-18 16:01:11 +00:00
gingerBill 197b832992 Add vendor:directx and vendor:darwin packages for documentation generation 2022-02-18 15:56:53 +00:00
gingerBill 8f13724a4b Merge pull request #1504 from odin-lang/directx-packages
DirectX Package Support
2022-02-17 23:15:38 +00:00
gingerBill 746d5fc322 Correct D3D packages 2022-02-17 20:48:50 +00:00
gingerBill ffc45e8cc2 Add intrinsics.constant_utf16_cstring 2022-02-17 20:48:37 +00:00
CiD- bea2f36443 improve entry point check logic 2022-02-17 10:48:30 -05:00
gingerBill f138f71fa6 Add UUID pointer values 2022-02-17 13:14:21 +00:00
Jeroen van Rijn 89b7a3f7ac Merge pull request #1506 from zacharycarter/patch-1
Adding capture procedures to user32
2022-02-17 13:59:52 +01:00
gingerBill 75e15b05b0 Correct alias 2022-02-17 12:46:04 +00:00
Tail Wag Games 78eb388110 Adding capture procedures to user32
Adding `GetCapture`, `SetCapture` and `ReleaseCapture` functions - https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcapture
2022-02-17 00:58:38 -06:00
CiD- df23cf47c6 fix odin test 2022-02-16 22:08:39 -05:00
gingerBill 002ac6a1b7 Add vendor:directx packages: dxgi, d3d11, and d3d12
TODO: enums marked with `bit_set` may need conversions
2022-02-16 21:26:34 +00:00
Jeroen van Rijn 40e4536887 Merge pull request #1502 from colrdavidson/mainline-fast
avoid memset on stats
2022-02-16 17:24:29 +01:00
Colin Davidson 536bf61323 avoid memset on stats 2022-02-16 08:14:11 -08:00
gingerBill c76bdced55 Merge branch 'master' into directx-packages 2022-02-16 16:05:46 +00:00
gingerBill 459ea5f4f6 Fix typo 2022-02-16 16:05:28 +00:00
gingerBill 8e8a075a22 Merge branch 'master' into directx-packages 2022-02-16 16:04:20 +00:00
gingerBill db6bd9b358 Allow sysv and win64 calling conventions to be used on any platform on amd64 2022-02-16 16:03:49 +00:00
gingerBill 42ad54c28e Improve metadata for context 2022-02-16 15:18:22 +00:00
gingerBill 1857bc7b02 Improve slice bounds checking runtime error messages 2022-02-16 14:51:54 +00:00
gingerBill e011d812ca Improve debug information for direct procedure parmaters 2022-02-16 14:39:08 +00:00
gingerBill 0738822dda Change how parameter and variables are given debug values 2022-02-16 13:25:31 +00:00
gingerBill 2213722776 Change debug declare to value 2022-02-16 12:37:22 +00:00
gingerBill 65dedbb1ca Add #subtype struct field prefix, required to have a COM interface hierarchy 2022-02-16 11:54:15 +00:00
gingerBill 0e69993d39 Add init and copy to all Objects 2022-02-16 00:17:07 +00:00
gingerBill 135091ddbe Correct import paths 2022-02-16 00:14:16 +00:00
gingerBill d64e3b672c Add darwin build tags 2022-02-16 00:12:31 +00:00
gingerBill a3bcacee27 Move Objective-C libraries located in core:sys/darwin/* to vendor:darwin/* 2022-02-16 00:06:25 +00:00
Jeroen van Rijn 855e7beab1 Merge pull request #1488 from colrdavidson/master
Add fork and personality
2022-02-15 21:04:09 +01:00
gingerBill edc13c29df Merge pull request #1331 from DanielGavin/parser-fault-recovery
Recover from closing brace not found in field list
2022-02-15 16:26:16 +00:00
gingerBill 21864d8d51 Improve BAD ENUM VALUE message in fmt #1496 2022-02-15 16:25:28 +00:00
gingerBill d45ff0694d Merge pull request #1438 from odin-lang/odin-global-constants-as-enums
Odin global constants as enums
2022-02-15 16:18:07 +00:00
gingerBill d695a8a526 Update os_darwin.odin 2022-02-15 16:02:14 +00:00
gingerBill 0380a288a9 Minor fix for -vet 2022-02-15 15:58:44 +00:00
gingerBill 1d4d0a3e1a Strip unneeded semicolons 2022-02-15 15:56:11 +00:00
gingerBill 9e98494fff Merge pull request #1482 from odin-lang/objc-intrinsics
Improve support Objective-C code through intrinsics and Metal API
2022-02-15 15:48:56 +00:00
gingerBill 86d334282c Merge pull request #1445 from Platin21/feature/darwin_systemcalls
Feature/darwin svc/syscall wrappers+id's
2022-02-15 15:48:20 +00:00
gingerBill 9cf937fef0 Merge pull request #1430 from DanielGavin/parser-fix
Fix return stmt when it's one lined(check for close brace).
2022-02-15 15:47:40 +00:00
gingerBill f5697dd7f2 Merge branch 'master' into odin-global-constants-as-enums 2022-02-15 15:47:24 +00:00
gingerBill a23ee1edc1 Merge pull request #1500 from thePHTest/master
Add 'odin run -help' info for specifying args
2022-02-15 15:46:27 +00:00
gingerBill 9dcb5c075a Merge pull request #1474 from Kelimion/tracking-example
mem: Add `doc.odin` with `Tracking_Allocator` example.
2022-02-15 15:46:19 +00:00
gingerBill 803648be89 Minor aesthetic clean ups of Foundation 2022-02-15 15:34:07 +00:00
gingerBill 3ab5db8297 Add README.md 2022-02-15 15:17:21 +00:00
gingerBill 3380ece4a1 Add utility calls for creating buffers from slices 2022-02-15 15:16:48 +00:00
gingerBill 0e5928ff39 Correct pseudo selector code generation 2022-02-15 15:16:30 +00:00
Phil H e6e04fc6c8 Add 'odin run -help' info for specifying args 2022-02-14 22:15:55 -08:00
gingerBill 753cceea82 Minor changes to method names on NS.String 2022-02-14 18:34:55 +00:00
gingerBill 32c7e81745 Use objc_allocateClassPair for intrinsics.objc_register_class 2022-02-14 18:32:10 +00:00
gingerBill 03aec70287 Change objc_class_name to objc_name with objc_is_class_method 2022-02-14 17:31:55 +00:00
gingerBill e69738c079 Minor style change 2022-02-14 17:23:14 +00:00
gingerBill 1afa7967f2 Fix method names 2022-02-14 17:09:30 +00:00
gingerBill 643e36b87b Improve Texture method names 2022-02-14 17:07:18 +00:00
gingerBill 3d2405ac2c Correct more method types 2022-02-14 17:02:05 +00:00
gingerBill 7392a3047a Add RenderPipeline missing types and methods 2022-02-14 16:58:56 +00:00
gingerBill 60f4d8f1ec Correct Render Pass types 2022-02-14 16:46:27 +00:00
gingerBill 7b42cbea20 Improve draw method names on RenderCommandEncoder 2022-02-14 16:42:53 +00:00
gingerBill 4cc597f4df RasterizationRate improvements 2022-02-14 16:32:54 +00:00
gingerBill 934e66ab3b More improvements 2022-02-14 16:26:42 +00:00
gingerBill b755609438 Improve Library related stuff 2022-02-14 16:25:20 +00:00
gingerBill 83d63e572a Improve indirect stuff 2022-02-14 16:21:00 +00:00
gingerBill 5212f62f54 Improve many methods with WithDescriptor suffixes 2022-02-14 16:18:23 +00:00
gingerBill 4d0fd4cf19 Correct device() usage 2022-02-14 15:56:32 +00:00
gingerBill e47953f7ca Improve procedure signature and names 2022-02-14 15:45:02 +00:00
gingerBill 47f3773146 Correct Depth classes 2022-02-14 15:18:38 +00:00
gingerBill 31c6ecad34 Correct Counter classes 2022-02-14 15:15:32 +00:00
gingerBill af6e53c05c Improve Compute classes 2022-02-14 15:14:41 +00:00
gingerBill 153140eb8f Improve ComputeCommandEncoder 2022-02-14 14:43:50 +00:00
gingerBill 6fef44c041 Improve CommandEncoder 2022-02-14 14:33:50 +00:00
gingerBill a88d149903 Improve CommandBuffer 2022-02-14 14:33:02 +00:00
gingerBill f9fc488399 Correct CaptureScope 2022-02-14 14:26:35 +00:00
gingerBill bef806bef4 Update Capture Manager classes 2022-02-14 14:24:36 +00:00
gingerBill 95e9bbf99f Improve Buffer 2022-02-14 12:52:30 +00:00
gingerBill 5936fa8871 Correct Blit Pass 2022-02-14 12:46:46 +00:00
gingerBill 02646b789c Correct typo 2022-02-14 12:44:57 +00:00
gingerBill 09e9dca869 Improve BlitCommandEncoder 2022-02-14 12:43:01 +00:00
gingerBill 9a43c0672e Correct BinaryArchive 2022-02-14 12:36:28 +00:00
gingerBill 83a6169463 Update ArgumentEncoder 2022-02-14 12:32:45 +00:00
gingerBill debe2de5fe Correct Acceleration Structure Types 2022-02-14 12:12:23 +00:00
gingerBill ff7d591ebf Correct AccelerationStructure classes 2022-02-14 11:55:59 +00:00
gingerBill 7386ca9272 Add new objc intrinsics: objc_(register|find)_(selector|class) 2022-02-14 11:21:21 +00:00
gingerBill fd8b2e0b88 Merge branch 'master' into objc-intrinsics 2022-02-14 11:04:36 +00:00
gingerBill c34ae884ad Change to "object" 2022-02-14 11:04:29 +00:00
gingerBill 2e7157ae9c Correct bytes._split_iterator 2022-02-14 11:01:34 +00:00
gingerBill 441365b388 Set the macOS minimum version to 12 for ARM CPUs 2022-02-14 10:58:01 +00:00
gingerBill f561147190 Correct _split_iterator 2022-02-14 10:57:29 +00:00
gingerBill 2958c1d6aa Add new shorthand 2022-02-13 16:56:27 +00:00
gingerBill 9dc83bc1b3 Add more methods 2022-02-13 16:32:31 +00:00
gingerBill 88b1b2c629 Correct types 2022-02-13 15:11:45 +00:00
gingerBill 23bc643a81 Merge branch 'objc-intrinsics' of https://github.com/odin-lang/Odin into objc-intrinsics 2022-02-13 12:01:19 +00:00
gingerBill 41854bacf5 Add utility classes for dealing with Windows
Most for GLFW and SDL only
2022-02-13 11:54:40 +00:00
gingerBill cf528431f5 Merge pull request #1495 from FancyKillerPanda/master
Updated vendor/sdl2/ttf LIB and DLL.
2022-02-12 23:46:44 +00:00
FancyKillerPanda e59064dd59 Updated vendor/sdl2/ttf LIB and DLL. 2022-02-13 10:33:48 +11:00
gingerBill 8966294823 Correct method name 2022-02-12 22:03:15 +00:00
gingerBill b8479ea79d Merge branch 'master' into objc-intrinsics 2022-02-12 21:49:48 +00:00
gingerBill e2aa8f426d Improve type hierarchy and method names 2022-02-12 21:45:34 +00:00
gingerBill 39a0f8c96a Use distinct array types 2022-02-12 21:28:56 +00:00
gingerBill b647b45ba5 Remove temp file 2022-02-12 21:25:20 +00:00
gingerBill 5fe9aa919b Correct types in methods 2022-02-12 21:24:28 +00:00
gingerBill ff5d6a994b Move vendor:Metal to core:sys/darwin/Metal 2022-02-12 17:59:40 +00:00
gingerBill ae3b95b194 #force_inline procedures and move foreign procedures to a separate file 2022-02-12 17:46:19 +00:00
gingerBill acaae1357c Update Metal for the full API
Methods need better names
2022-02-12 17:30:32 +00:00
gingerBill f8afda3b22 Add more objc attributes 2022-02-11 22:54:51 +00:00
Colin Davidson 31f544c258 Merge branch 'odin-lang:master' into master 2022-02-11 08:25:17 -08:00
Mikkel Hjortshøj 1c57d1c019 Update nightly.yml 2022-02-11 17:22:33 +01:00
Mikkel Hjortshøj 251edf7bc7 Update ci.yml 2022-02-11 17:22:14 +01:00
Colin Davidson f77cd5533d Add fork and personality 2022-02-11 08:10:48 -08:00
gingerBill 416413bebf Begin work on Metal 2022-02-10 14:35:10 +00:00
gingerBill c3809d7b84 Fix typo 2022-02-09 21:46:26 +00:00
gingerBill 42a1c58a80 Update Foundation linking 2022-02-09 21:42:20 +00:00
gingerBill b6abaf739c Add missing calls for Object; Add scoped_autoreleasepool 2022-02-09 12:29:52 +00:00
gingerBill ef98e92e8d Remove unneeded file 2022-02-09 12:23:41 +00:00
gingerBill 768c2684d0 Add NSBundle, NSError, NSEnumerator 2022-02-09 12:19:59 +00:00
gingerBill 5f2514db63 Add NSNumber and NSURL 2022-02-09 11:50:11 +00:00
gingerBill b95ade40c0 Begin work on core:sys/darwin/Foundation 2022-02-09 00:19:20 +00:00
gingerBill 340838c878 Add procs_darwin.odin 2022-02-08 23:00:00 +00:00
gingerBill c5d348515d Add intrinsics.type_is_subtype_of; intrinsics.objc_selector_name 2022-02-08 22:59:37 +00:00
gingerBill 05dd3d490d Correct objc_class propagation for parapoly structs 2022-02-08 17:33:55 +00:00
gingerBill 0cc40db565 Begin work on support objc intrinsics 2022-02-08 17:04:55 +00:00
Jeroen van Rijn 546faab0cb Merge pull request #1481 from jasonKercher/vet_fix
fix `-vet` for `filepath/match.odin`
2022-02-08 15:27:51 +01:00
CiD- 83e9a6b417 fix -vet for filepath/match.odin 2022-02-08 09:21:43 -05:00
gingerBill 30bb2382aa Correct simple boolean intrinsics 2022-02-08 11:48:59 +00:00
gingerBill 61a0b4ec5a Merge pull request #1480 from NoahR02/opensimplex2_noise
Adds OpenSimplex Noise to Odin.
2022-02-08 11:42:17 +00:00
NoahR02 accb35506f Ports OpenSimplex2 from https://github.com/KdotJPG/OpenSimplex2 to Odin. Adds tests for the noise procedures. 2022-02-08 06:25:07 -05:00
NoahR02 817bc7434d Ports OpenSimplex2 from https://github.com/KdotJPG/OpenSimplex2 to Odin. Adds tests for the noise procedures. 2022-02-08 06:16:10 -05:00
gingerBill 3c2ed3bb69 Correct //+private file bug 2022-02-07 11:37:13 +00:00
gingerBill 9cbf46e689 Fix constant multi pointer declarations through integers 2022-02-07 11:00:38 +00:00
gingerBill ad6ea3d6aa Replace any with union for subtyping in core:odin/ast 2022-02-06 13:31:16 +00:00
gingerBill cda9fd5271 Add tag to ast.Comp_Lit 2022-02-06 11:59:12 +00:00
gingerBill 0c16f27814 Update parser for #sparse 2022-02-06 11:50:27 +00:00
gingerBill 19aec13a10 Support rank-2 arrays (matrix-like) for transpose 2022-02-06 11:42:59 +00:00
Jeroen van Rijn e896956275 Merge pull request #1475 from Platin21/feature/fix-odin-fmt
Feature/fix odin fmt
2022-02-05 23:22:07 +01:00
Platin21 c59c6e98a5 Merge branch 'odin-lang:master' into feature/fix-odin-fmt 2022-02-05 23:14:44 +01:00
Platin21 8b1100bf2b os.open does r/d as default which makes a call to open a dir invalid this should fix this problem 2022-02-05 23:12:55 +01:00
Jeroen van Rijn a3d99765cc mem: Add doc.odin with Tracking_Allocator example. 2022-02-05 22:18:22 +01:00
Platin21 a724573bb3 Fixes fopendir and readdir_r for arm64 or seemingly doing so 2022-02-05 21:16:58 +01:00
Jeroen van Rijn 25769f139a Merge pull request #1471 from Platin21/feature/fix-odin-fmt
Feature/fix odin fmt
2022-02-05 21:00:52 +01:00
Platin21 3edf638cc6 Fixed Typo 2022-02-05 20:54:27 +01:00
Platin21 de7e612186 Ignores DS_Store files which MacOS uses for Indexing or some crap 2022-02-05 20:45:55 +01:00
Platin21 a571153458 Adds missing calls for os 2022-02-05 20:45:32 +01:00
Jeroen van Rijn ada58c66fa Merge pull request #1469 from ap29600/bit_iterator
add `iterator` to `core:container/bit_array`
2022-02-05 18:50:33 +01:00
ap29600 697f8c7ee6 replace a branch with max in core:container/bit_array.set 2022-02-05 18:46:25 +01:00
Andrea Piseri b6ebfe4b2c rename iterator procedures 2022-02-05 18:11:48 +01:00
Andrea Piseri bccbdefde9 Update interface to allow more modes of iteration
It's now possible to iterate over:
- all keys in the range min_value ..= max_value, with `iterate_all`
- all set keys in the bit array, with `iterate_set`
- all unset keys in the range min_value ..= max_value, with `iterate_unset`

`Bit_Array` now stores the `max_value` provided during construction, and
updates it when a key that was previously out of range is set.
2022-02-05 18:00:59 +01:00
gingerBill 445ca70521 Correct implicit union cast 2022-02-05 16:11:48 +00:00
gingerBill c6ab8f82c8 Code refactor to aid development 2022-02-05 15:17:47 +00:00
gingerBill 67ce0ec29f Improve printing for unhandled cases by adding a new line before the cases 2022-02-05 14:58:13 +00:00
gingerBill 23c3573c30 Minor correction to error message suggestion 2022-02-05 14:56:06 +00:00
gingerBill a4308e7246 Improve union variant assignment determination 2022-02-05 14:45:59 +00:00
gingerBill 3439139b1c Minor clean up 2022-02-05 14:34:29 +00:00
gingerBill cf246f65ff Add check for variables which are both shadowing and unused by default 2022-02-05 14:31:22 +00:00
gingerBill dd84b61cc8 Correct add_to_seen_map logic 2022-02-05 14:07:17 +00:00
gingerBill b8c4bf2afb Add #partial [Enum]Type{...} support to check for missing enumerated array fields 2022-02-05 14:02:21 +00:00
gingerBill e870041fe6 Fix #sparse usage 2022-02-05 13:11:41 +00:00
gingerBill 6418ec3b21 Correct #sparse usage and error messages 2022-02-05 13:09:16 +00:00
gingerBill 2bcc7b0064 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-05 13:01:21 +00:00
gingerBill 97be867103 Rename #partial[Enum]Type to #sparse[Enum]Type for non-contiguous enum fields 2022-02-05 13:01:15 +00:00
gingerBill fb710f8cbf Merge pull request #1376 from jasonKercher/master
Added zeroing to new memory regions from _unix_realloc
2022-02-05 12:26:10 +00:00
gingerBill 1553137c23 Change behaviour of A :: distinct Enum_Type to be more intuitive 2022-02-05 00:04:02 +00:00
gingerBill d5384c5aa4 Only check idents in the alias (of alias)+ problem 2022-02-04 22:45:13 +00:00
gingerBill 3a81f2ab89 Correct the type aliasing problem, caused by aliases (of aliases)+ 2022-02-04 22:40:15 +00:00
ap29600 b54fc96b1e rename iterator proc to next, add named return values 2022-02-04 22:39:47 +01:00
Andrea Piseri 48af78e469 add iterator to core:container/bit_array 2022-02-04 22:12:07 +01:00
gingerBill abb26e0bea Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-04 12:08:24 +00:00
gingerBill 76edfae0e0 core:container/topological_sort 2022-02-04 12:08:20 +00:00
gingerBill a5298e17ec Merge pull request #1467 from ap29600/u128_endian_swap
fix logic in bswap_128
2022-02-03 15:06:12 +00:00
Andrea Piseri cf9f3d5e2d fix logic in bswap_128 2022-02-03 15:50:39 +01:00
gingerBill 35c90fe124 Fix type alias declaration evaluation problem (#854 #1439) 2022-02-03 13:34:31 +00:00
gingerBill df8bdac33f Initialize the global_rand with the intrinsics.read_cycle_counter() value 2022-02-03 00:31:36 +00:00
gingerBill b4f7a527c2 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-02-02 23:38:40 +00:00
gingerBill 35533a7baa Update core:container/lru to support clear and take a boolean to indicate whether or not to call the on_remove procedure on clear or destroy 2022-02-02 23:38:32 +00:00
gingerBill 2c9ed7464f Merge pull request #1465 from ap29600/reflect_is_nil_fix
Fix logic in `is_nil` procedure
2022-02-02 19:36:25 +00:00
Andrea Piseri e190c024fd Fix logic in is_nil procedure: a non_nil slice means there is data to check. 2022-02-02 20:07:38 +01:00
gingerBill e250475bf9 Merge pull request #1457 from DanielGavin/parser-inline
Fix core:odin/parser not setting the inline flag correctly.
2022-02-02 16:32:09 +00:00
gingerBill 5db603ded2 Minor sanity clean up 2022-02-02 15:39:41 +00:00
gingerBill 78815778ee Add //+private file to complement //+private (//+private package) 2022-02-02 15:28:49 +00:00
gingerBill a04d849e30 core:container/lru 2022-02-01 15:24:37 +00:00
gingerBill 8c9505505a Add allocator parameter to rand.perm 2022-02-01 15:23:49 +00:00
gingerBill eac74631ec Correct debug information logic for procedure parameters 2022-02-01 14:11:19 +00:00
gingerBill 85706d559d Fix typo 2022-01-31 20:19:46 +00:00
gingerBill 67ba05cb7c Correct false positive check in check_unique_package_names 2022-01-31 19:33:02 +00:00
gingerBill 2f1aeaf757 Remove the unneeded $ 2022-01-31 15:56:40 +00:00
gingerBill 14a17fb36f Add slice.stable_sort* procedures 2022-01-31 15:55:52 +00:00
gingerBill 1a9ec776cb Unify logic for slice.sort* related procedures 2022-01-31 12:43:20 +00:00
gingerBill da1edac56d Enforce -strict-style in CI 2022-01-31 11:29:05 +00:00
gingerBill 44ec95a983 Fix all_main.odin 2022-01-30 21:55:55 +00:00
gingerBill 1502066303 Correct CI 2022-01-30 21:43:42 +00:00
gingerBill 35a826a0fd Update CI to do odin check examples/all 2022-01-30 21:38:34 +00:00
gingerBill ebb8ca7c26 Add round to linalg_glsl_math.odin 2022-01-30 21:35:05 +00:00
gingerBill 763de44853 Merge pull request #1461 from AquaGeneral/master
Added round to HLSL and GLSL, and isinf/isfinite + isnan to HLSL
2022-01-30 10:46:13 +00:00
Jesse Stiller 62cc752066 Added round to HLSL and GLSL, and isinf/isfinite + isnan to HLSL 2022-01-30 13:57:01 +10:00
gingerBill 965b962b29 Merge pull request #1459 from powerc9000/clay-macos-fixes
Fix mutex and conditions trying to be destroyed twice in unix
2022-01-28 00:24:29 +00:00
powerc9000 2f3c5336d9 Fix mutex and conditions trying to be destroyed twice in unix 2022-01-27 15:38:16 -07:00
gingerBill 3824937295 Remove debug code 2022-01-27 16:30:22 +00:00
gingerBill fc8ddcef5c Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-27 16:09:44 +00:00
gingerBill 3165b7cf95 Add rand.exp_float64 2022-01-27 16:09:33 +00:00
gingerBill 5eea23cf76 Fix typo 2022-01-27 16:09:05 +00:00
gingerBill 2aa783179e Update doc_format.odin 2022-01-27 16:08:58 +00:00
gingerBill 24e7356825 Add #no_type_assert and #type_assert to disable implicit type assertions with x.(T) 2022-01-27 16:08:47 +00:00
Jeroen van Rijn 2fcba25e50 Merge pull request #1458 from Kelimion/zlib_fix
Fix DEFLATE stored block handling.
2022-01-27 15:10:33 +01:00
Jeroen van Rijn 28bc274449 Fix DEFLATE stored block handling. 2022-01-27 14:58:45 +01:00
Daniel Gavin ff5e036773 Trim whitespaces 2022-01-27 14:27:26 +01:00
Daniel Gavin 4dc29d141f Fix core:odin/parser not setting the inline flag correctly. 2022-01-27 14:24:33 +01:00
Daniel Gavin 8ecee32e1c Merge remote-tracking branch 'upstream/master' into parser-fix 2022-01-27 13:58:41 +01:00
gingerBill 16786aac78 Correct int31_max etc 2022-01-27 12:33:34 +00:00
gingerBill 32b37f3429 Support built-in procedures for doc format 2022-01-27 00:08:05 +00:00
gingerBill 5808793cae Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-26 23:31:53 +00:00
gingerBill 7e11f3cc4b Update doc format to allow for aliases 2022-01-26 23:31:47 +00:00
gingerBill 714ab516c5 Merge pull request #1454 from jasonKercher/fix_segfault
avoid segfault in llvm_backend_general.cpp on map resize
2022-01-26 19:56:59 +00:00
CiD- 498f68c06b avoid segfault on map resize 2022-01-26 14:37:15 -05:00
gingerBill 070b450768 Add ODIN_ERROR_POS_STYLE constant and change runtime.print_caller_location based on that constant 2022-01-26 17:34:39 +00:00
gingerBill 74174eb4ae Remove spurious ) 2022-01-26 16:38:12 +00:00
gingerBill b190404b21 Fix double map dereference indexing 2022-01-26 16:37:16 +00:00
gingerBill 081a5a52a6 Add ODIN_ERROR_POS_STYLE environment variable
Allowing for two different error message styles:
default or odin
    path(line:column) message
unix
    path:line:column: message
2022-01-26 16:09:22 +00:00
gingerBill fb86c23dbd Keep -vet happy 2022-01-25 16:41:31 +00:00
gingerBill cb6a4ebf60 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-25 16:40:31 +00:00
gingerBill 1bf8328606 Strip unneeded semicolons 2022-01-25 16:40:25 +00:00
Jeroen van Rijn 6a7f39453b Merge pull request #1450 from Kelimion/bit_array
bit_array: Fix initial size.
2022-01-25 17:14:42 +01:00
Jeroen van Rijn 515fd2a228 bit_array: Fix initial size. 2022-01-25 17:08:32 +01:00
gingerBill dd3322ac1f Update all_main.odin to include all the crypto packages 2022-01-25 14:34:48 +00:00
gingerBill f16f1d932e Fix #1448 2022-01-25 14:24:15 +00:00
gingerBill a3e7b2baa1 Revert change 2022-01-25 12:42:45 +00:00
gingerBill fadf9b5309 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-25 12:39:12 +00:00
gingerBill f6a087775e Disable early return from check_proc_info 2022-01-25 12:39:06 +00:00
Jeroen van Rijn d5f7e181a0 Merge pull request #1449 from Kelimion/zlib_change
zlib: update Huffman builder.
2022-01-25 12:23:34 +01:00
Jeroen van Rijn 65f8722afc zlib: update Huffman builder. 2022-01-25 12:18:10 +01:00
gingerBill c0479f1564 Handle line comment better 2022-01-24 23:42:04 +00:00
gingerBill fe0b5bf4e2 Parse comments on enums fields 2022-01-24 23:28:59 +00:00
gingerBill f20105ddfe Update docs for packages fmt and io 2022-01-24 23:07:06 +00:00
Daniel Gavin 6a7d821fcc Merge remote-tracking branch 'upstream/master' into parser-fix 2022-01-24 16:58:39 +01:00
gingerBill 42ab882db4 Remove debug code 2022-01-24 15:56:26 +00:00
gingerBill dcc9e61362 Correct string_append_token 2022-01-24 14:52:43 +00:00
gingerBill 2554c72bb2 Update CommentGroup parsing for struct types 2022-01-24 14:47:33 +00:00
gingerBill 49872e40dc Comment out calls 2022-01-24 14:46:56 +00:00
gingerBill 849fe01e70 Add lb_add_debug_local_variable call to procedure arguments 2022-01-24 14:13:24 +00:00
Platin21 1243b1a58c Fixed cyclic imports which where not needed 2022-01-23 23:16:57 +01:00
Platin21 ab3bae5c02 Fixed package name 2022-01-23 23:14:46 +01:00
Platin21 540c5400a0 Adds several system calls and the beginning of odin wrappers for them
This also adds all systemcall numbers from the xnu kernel / and additional helpers for some of the calls to make it easier to call them from odin
2022-01-23 23:13:32 +01:00
gingerBill d269dbcd40 Add comment for the internals of assert 2022-01-23 22:01:54 +00:00
gingerBill 18e639f59b Add strings.split_lines* procedures 2022-01-23 21:35:03 +00:00
gingerBill 6ad262c2df Migrate odin-html-docs to pkg.odin-lang.org repo 2022-01-23 16:52:08 +00:00
gingerBill 10b97a1b39 Update style.css 2022-01-23 16:36:37 +00:00
gingerBill 56b4e0a3c3 Fix #1267 2022-01-23 15:40:46 +00:00
gingerBill 27dbe84f79 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-23 09:53:56 +00:00
gingerBill 0711d4e5fe Correct bit_set printing 2022-01-23 09:53:50 +00:00
Jeroen van Rijn 1e46537959 Merge pull request #1443 from graphitemaster/patch-1
Fix fread definition
2022-01-23 09:39:43 +01:00
Dale Weiler a5e1693774 Fix fread definition 2022-01-23 03:12:59 -05:00
Daniel Gavin 01e29bf27e Merge remote-tracking branch 'upstream/master' into parser-fix 2022-01-23 01:38:15 +01:00
gingerBill 63771bc6e8 Merge pull request #1441 from Platin21/fix/multiple-llvm-versions
Makes it possible to use llvm 12 13 and 11 for building on macOS
2022-01-22 20:22:00 +00:00
Platin21 8516e2e7e3 Changed match to be arbitrary width
(cant do exact match as we never know how much subversion's llvm does)
2022-01-22 20:50:05 +01:00
gingerBill b3c3e41706 Correct directory comment printing 2022-01-22 19:49:46 +00:00
gingerBill 59f3a009fa Update header-lower.txt.html 2022-01-22 19:46:22 +00:00
Platin21 9bc5b84c4d Removes maybe unsupported versions 2022-01-22 20:40:04 +01:00
gingerBill f9265c14bf Update footer.txt.html 2022-01-22 19:37:35 +00:00
Platin21 9c1e1a63a2 Added pattern function so we can match whatever llvm versions we want
Right now we match every version that is 13 something for arm64 on macOS
And for x86 we allow any above 11 and including 11
2022-01-22 20:29:57 +01:00
gingerBill 4dc5839e3d Add header-lower.txt.html 2022-01-22 17:09:10 +00:00
gingerBill fdcb9deaff Generate core and vendor library collection; add package sidebar for the entire collection 2022-01-22 17:07:24 +00:00
gingerBill fe6539fad9 Add more to examples/all/all_vendor.odin 2022-01-22 17:03:55 +00:00
Platin21 0e06383620 Changed make file so that it allows for multiple LLVM versions instead of a single one on Darwin 2022-01-22 17:34:43 +01:00
gingerBill 6223f48c3f Update tests 2022-01-20 20:08:24 +00:00
gingerBill f2f20def37 Update demo.odin 2022-01-20 20:02:41 +00:00
gingerBill 77b91352ae Add Odin_OS_Type and Odin_Arch_Type to core:runtime 2022-01-20 19:58:35 +00:00
gingerBill 3d7d347192 Convert ODIN_OS and ODIN_ARCH to use enums rather than use strings 2022-01-20 19:56:05 +00:00
CiD- e5868e3205 add zeroing regardless of ODIN_OS 2022-01-20 10:17:47 -05:00
gingerBill cfbc1a447b Correct inverse and inverse_transpose for 2x2 matrices 2022-01-20 13:18:37 +00:00
gingerBill 1b23dd2257 Add home page 2022-01-20 01:02:26 +00:00
gingerBill b612edba5a Improve detail styling 2022-01-20 00:36:44 +00:00
gingerBill d39c05b183 Simplify tag printing 2022-01-20 00:19:58 +00:00
gingerBill 3a3cb521ab Support tag printing 2022-01-20 00:19:24 +00:00
gingerBill 5b97ff0b48 General improves including comment formatting 2022-01-20 00:13:26 +00:00
gingerBill 2b918ada4b Add .Private information to doc-format 2022-01-19 17:15:10 +00:00
gingerBill b5754b6ed9 Print examples correctly 2022-01-19 16:35:50 +00:00
gingerBill 07ee23f817 Simplify dir tree generation 2022-01-19 16:28:01 +00:00
gingerBill ecdaac9921 Unify are_types_identical_unique_tuples 2022-01-19 15:14:15 +00:00
gingerBill 5ff82fc113 Correct tuple name checking for doc writing 2022-01-19 15:11:42 +00:00
gingerBill 28a816ef25 Allow for entity grouping in structs and procedure signatures with the Odin doc-format 2022-01-19 14:57:27 +00:00
gingerBill 6bdb210ad8 More improvements to the styling 2022-01-19 13:34:54 +00:00
gingerBill db08847f9a Improve rendering to match the main website's CSS 2022-01-19 13:20:38 +00:00
gingerBill 841c428273 Merge pull request #1433 from odin-lang/html-docs-printer
Initial Work on HTML Docs Printer
2022-01-18 11:03:41 +00:00
gingerBill 6b830f42b6 Improve stylization with collapsible directories; Fix name padding 2022-01-17 23:48:46 +00:00
gingerBill fb01dfe048 Improve docs_writer.cpp 2022-01-17 22:17:07 +00:00
gingerBill c7a9c8274f Improve type printing 2022-01-17 22:16:32 +00:00
gingerBill cafb6e5587 Correct //+private for odin doc 2022-01-17 21:33:20 +00:00
gingerBill e9ae6e20e8 Fix code, source code links, and add recursive make directory 2022-01-17 20:50:40 +00:00
gingerBill 2ca2dbcc92 Correct distinct printing 2022-01-17 19:23:24 +00:00
gingerBill 0d4642825f Correct package docs parsing 2022-01-17 19:07:25 +00:00
gingerBill 8eda756714 Add printing for constants, variables, types, and procedure groups 2022-01-17 19:01:16 +00:00
gingerBill c85ac955f7 Simplify docs to hide the copyright 2022-01-17 19:00:47 +00:00
gingerBill 97922406fe Improve printing for record types 2022-01-17 18:23:30 +00:00
gingerBill 76ccce2942 Begin work on a html doc printer 2022-01-17 17:57:55 +00:00
gingerBill 686dbb4421 Correct odin doc comment printing 2022-01-17 14:43:42 +00:00
gingerBill cd6898439e Comment out link_section on procedures 2022-01-17 12:17:13 +00:00
Daniel Gavin 96d7c4ffdf Merge remote-tracking branch 'upstream/master' into parser-fix 2022-01-17 13:15:44 +01:00
gingerBill 95620aaf2a Update examples/all 2022-01-17 11:48:15 +00:00
gingerBill 1d293749c2 Move core:path to core:path/slashpath
This is to reduce the confusion that occurs between that package and the `core:path/filepath` package
2022-01-17 11:38:15 +00:00
gingerBill 2d35a5c1af Merge pull request #1431 from AquaGeneral/master
Extraneous parameters in hlsl/glsl.saturate removed
2022-01-17 10:52:19 +00:00
Jesse Stiller d4ea02a877 Extraneous parameters in hlsl/glsl.saturate removed
This is a breaking change to anyone who used glsl/hlsl.saturate functions prior, but the y and z parameters never were used and do not conform to how the saturate function works in HLSL:  https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-saturate

Note however GLSL does not contain a saturate function, but removing it does not accomplish anything good IMO.
2022-01-17 12:19:06 +10:00
Daniel Gavin f19325cbe0 Merge remote-tracking branch 'upstream/master' into parser-fix 2022-01-16 13:54:22 +01:00
gingerBill 2a325b3da0 Update ODIN_ENDIAN usage 2022-01-16 12:25:39 +00:00
Daniel Gavin d57ec4a11d Fix return stmt when it's one lined(check for close brace). 2022-01-16 13:20:12 +01:00
gingerBill f0529535e0 ODIN_ENDIAN changed to an enum constant; ODIN_ENUM_STRING is the new string version of the old constant 2022-01-15 17:53:18 +00:00
gingerBill 3f59c45740 Remove main creation in llvm_backend.cpp and have it done purely in the runtime package (partial bootstrapping) 2022-01-15 17:42:10 +00:00
gingerBill 29ebe0c3c9 Rename architecture 386 to i386 2022-01-15 17:40:00 +00:00
gingerBill 6c48670819 Make ODIN_BUILD_MODE a enum type 2022-01-15 17:34:35 +00:00
gingerBill 51dcbc80c3 Add LLVMAddMergedLoadStoreMotionPass on -debug -opt:0 2022-01-15 16:26:14 +00:00
gingerBill 9ecbadd457 Simplify procedure parameters callee logic 2022-01-15 16:16:11 +00:00
gingerBill 79f32d7b71 Remove unused lbDefer kind 2022-01-15 16:03:37 +00:00
gingerBill 7501cc2f17 Remove dead code 2022-01-15 16:01:23 +00:00
gingerBill a390ef41f8 Fix swizzle logic within lb_build_assign_stmt_array 2022-01-15 15:55:01 +00:00
gingerBill bb9c2f7aad Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-15 15:38:15 +00:00
gingerBill 6aa80ee8e4 Correct _start as an entry point 2022-01-15 15:38:09 +00:00
Jeroen van Rijn 0741bc37cc Merge pull request #1427 from oskarnp/macos-linker-fix
Fix invalid linker flags passed to clang on macOS
2022-01-14 17:05:28 +01:00
oskarnp c6ed3fa4b5 Fix invalid linker flags passed to clang on macOS 2022-01-14 10:48:41 -05:00
Jeroen van Rijn e277102947 Merge pull request #1426 from jasonKercher/fix_queue
fix push_back and pop_front
2022-01-14 16:45:54 +01:00
CiD- 6cf5371d7d fix push_back and pop_front 2022-01-14 10:17:49 -05:00
gingerBill e15f714660 Define wasm _start entry point in Odin code 2022-01-13 15:18:47 +00:00
gingerBill 4f77151ebc Merge pull request #1389 from ap29600/slice_scanner
Add slice/scanner proc
2022-01-13 14:10:17 +00:00
gingerBill 9a46463078 Merge pull request #1399 from kleeon/master
Fixed wrong function name in vendor/OpenGL/README.md
2022-01-13 12:06:53 +00:00
gingerBill a0816bb581 Merge pull request #1424 from jasonKercher/os_linux
os_linux additions + libc to syscalls
2022-01-13 12:06:40 +00:00
gingerBill b33ca6651e Rename proc_* to entry_* 2022-01-13 12:05:22 +00:00
gingerBill 315a08f33f Add main to proc_unix.odin 2022-01-13 12:04:42 +00:00
Jeroen van Rijn 50668fa7a6 Merge pull request #1425 from graphitemaster/more_linux_shared_library_fixes
Fixes for shared library initialization and finalization
2022-01-13 06:36:19 +01:00
Dale Weiler ee260986a9 more fixes 2022-01-13 00:19:04 -05:00
gingerBill c9bc759624 Correct calling convention 2022-01-12 23:04:31 +00:00
gingerBill 80f175cdb0 Add empty main dynamic builds for *nix systems 2022-01-12 20:40:34 +00:00
gingerBill 8f03811842 Fix typo 2022-01-12 20:30:34 +00:00
gingerBill 3def94505e Add dynamic to error message for -build-mode 2022-01-12 20:28:11 +00:00
gingerBill e30f16b1f3 Correct -init for *nix 2022-01-12 20:17:30 +00:00
gingerBill 7df93ea504 Initialize runtime.args__ through main 2022-01-12 20:16:46 +00:00
gingerBill 6209b02bf9 Add intrinsics._entry_point call to _odin_entry_point 2022-01-12 20:16:04 +00:00
gingerBill 75b7f2b9fe Correct -init for *nix to be a different procedure 2022-01-12 20:13:38 +00:00
gingerBill f1521aa980 Add proc_windows.odin for custom entry points 2022-01-12 20:10:23 +00:00
gingerBill fb0a3ab7c1 Correct linkage for entry point procedures on Windows 2022-01-12 20:07:17 +00:00
CiD- 8eaafd5242 check correct errno in _readlink 2022-01-12 14:51:49 -05:00
CiD- 774951e8c0 os_linux additions + libc to syscalls 2022-01-12 14:36:18 -05:00
gingerBill 5ec93677a0 Correct look for entry point in llvm backend (Windows only currently) 2022-01-12 19:27:49 +00:00
gingerBill 7e4067c44c Begin work to move entry point code to Odin itself rather than in C++ side 2022-01-12 19:19:43 +00:00
gingerBill f2f6c3c67d Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-11 10:56:13 +00:00
gingerBill 847b05013f Disable DEFAULT_TO_THREADED_CHECKER until race condition is found 2022-01-11 10:56:07 +00:00
gingerBill d308473075 Merge pull request #1421 from graphitemaster/linux_shared_library_fixes
Linux shared library fixes
2022-01-10 23:18:04 +00:00
Dale Weiler 4334dbe69a disable this warning 2022-01-10 18:00:38 -05:00
Dale Weiler 8f91e9307c shared library fixes 2022-01-10 17:57:33 -05:00
gingerBill 32ec1162bf Use more {} ctor 2022-01-10 14:52:47 +00:00
gingerBill 7cc265e14c Add mutex guards for signature scopes 2022-01-10 14:50:28 +00:00
gingerBill 6f3e450c50 Move error handling code to a separate file 2022-01-10 14:03:36 +00:00
gingerBill cb1080d56c Fix check_procedure_bodies to allow multiple threads caused by a typo 2022-01-10 13:31:34 +00:00
gingerBill 80bd1eb615 Fix polymorphic matrix element with a minor hack 2022-01-10 12:19:49 +00:00
gingerBill fb53402914 Merge pull request #1402 from jasonKercher/syscalls
add more Linux syscalls
2022-01-10 11:50:45 +00:00
gingerBill 731853ce78 Merge pull request #1416 from Naboris/utf16-typo
fix typo in utf16 decode_to_utf8
2022-01-10 11:50:04 +00:00
gingerBill f0260e9771 Merge pull request #1420 from odin-lang/linalg-to-use-matrix-type
Update matrix types to be the native Odin `matrix` types
2022-01-10 11:49:49 +00:00
gingerBill af612bc7e9 Update matrix types to be the native Odin matrix types 2022-01-10 11:32:27 +00:00
Jeroen van Rijn d76dd95c0b Merge pull request #1418 from wbogocki/patch-1
Fix link to Odin blog
2022-01-09 16:10:50 +01:00
Wojciech Bogócki 1cff72ad62 Fix link to Odin blog 2022-01-09 22:43:12 +08:00
Naboris 773cfac449 fix typo 2022-01-08 09:49:21 +01:00
Jeroen van Rijn b02f2953ac Merge pull request #1410 from Kelimion/sort_map
Fix unused imports.
2022-01-07 06:47:54 +01:00
Jeroen van Rijn 566a750899 Fix unused imports. 2022-01-07 06:12:00 +01:00
Jeroen van Rijn 1d1d684cbc Merge pull request #1407 from Platin21/feature/fix-supervisor-call
Fix Syscall Intrinsic on ARM64 MacOS
2022-01-05 17:02:24 +01:00
Platin21 7a14acaa01 Fixes syscall intrinsic on macOS they use a slightly different section + register for the id 2022-01-05 16:49:58 +01:00
gingerBill 057174497a Merge pull request #1406 from terickson001/schar
add schar to core:c and core:c/libc
2022-01-05 00:50:24 +00:00
Tyler Erickson 8c9597b24b add schar to core:c and core:c/libc 2022-01-04 16:45:16 -08:00
gingerBill 72862ce30d Fix minor typo in c/frontend/preprocess 2022-01-04 11:48:18 +00:00
gingerBill d0f4cb1de4 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-01-04 11:47:05 +00:00
gingerBill 17613185e7 Support struct field tags in odin doc format 2022-01-04 11:44:34 +00:00
Jeroen van Rijn 00ff1fbca2 Merge pull request #1403 from Platin21/feature/fix-open-syscall
Fixes open system call (Thanks TIM!)
2022-01-03 20:48:09 +01:00
gingerBill f15bb0b424 Fix quaternion casting 2022-01-03 19:45:27 +00:00
gingerBill f818d0feb1 Fix #1344 2022-01-03 19:43:22 +00:00
Platin21 8ff6f95571 Removes the default create flag 2022-01-03 20:40:56 +01:00
Platin21 68e5f57e27 Fixes open system call (Thanks TIM!) 2022-01-03 20:34:57 +01:00
CiD- 38e5e13b3f add more Linux syscalls 2022-01-03 09:24:39 -05:00
gingerBill defc1672c3 Revert fix #1344 2022-01-03 13:48:12 +00:00
gingerBill 12f459b5fb Fix #1344 2022-01-03 13:12:39 +00:00
gingerBill e6b8f7e77a Fix #1398 2022-01-03 12:54:31 +00:00
gingerBill 236b08cb49 Fix #1356 2022-01-03 12:51:32 +00:00
gingerBill e4f28de3de Fix #1311 2022-01-03 12:14:01 +00:00
gingerBill 6543491148 Clean up code for queue (no logic changed) 2022-01-02 15:31:47 +00:00
gingerBill 3cbf9c3719 Fix #1381 2022-01-02 14:45:39 +00:00
gingerBill 50188f0308 Add sort.map_entries_by_key sort.map_entries_by_value 2022-01-01 17:13:11 +00:00
gingerBill a60b9735a2 Add core:container/queue 2022-01-01 15:46:22 +00:00
gingerBill a032a2ef32 Remove the hidden NUL byte past the end from bytes.clone 2022-01-01 15:33:19 +00:00
gingerBill f364ac60c2 Remove the hidden NUL byte past the end from strings.clone 2022-01-01 15:31:51 +00:00
gingerBill 43763ddfda Correct _shift_down logic 2022-01-01 13:44:37 +00:00
gingerBill 70ed280c5a Fix typo in priority_queue.odin and add default_swap_proc 2022-01-01 13:11:53 +00:00
gingerBill 0d7cb02386 Fix conversion from float to quaternion 2021-12-31 23:20:14 +00:00
gingerBill bdf66bb1e1 Correct abs type behaviour for quaternions 2021-12-31 22:54:12 +00:00
Jeroen van Rijn 9b5cfe2677 Merge pull request #1401 from zhibog/extend-crypto-api
Extended crypto Hash API by variants that write the result into a destinat…
2021-12-31 13:27:56 +01:00
zhibog 42033ea808 Extended crypto API by variants that write the result into a destination buffer, instead of returning it 2021-12-31 13:16:11 +01:00
gingerBill c7ff296bef Change the implementation of Priority_Queue to have a better interface that allows for a less and swap procedure 2021-12-30 13:42:10 +00:00
kleeon 750ee4ecdb Fixed wrong function name in README.md 2021-12-30 15:49:07 +03:00
gingerBill ed742846cb Correct lb_emit_ptr_offset bug caused by LLVMConstGEP assuming a signed index 2021-12-29 15:01:56 +00:00
gingerBill ed8b20da78 Add core:container/priority_queue 2021-12-29 14:38:39 +00:00
gingerBill c987b84292 Move bash.djbx33a to hash.odin 2021-12-29 12:24:47 +00:00
gingerBill a9b17b5a37 Add hash.djbx33a 2021-12-29 12:01:07 +00:00
gingerBill a66f859fb4 Minor improvements to core:container/small_array 2021-12-29 11:58:27 +00:00
gingerBill c46e7eda1d Add core:container/small_array 2021-12-29 11:26:22 +00:00
Andrea Piseri 92e70b9a58 use multipointers instead of simple pointers 2021-12-28 16:22:34 +01:00
Andrea Piseri 822da9d12d Merge branch 'master' into slice_scanner 2021-12-28 16:12:15 +01:00
Jeroen van Rijn b0817d136b Merge pull request #1354 from Kelimion/bit_vector
[core:container/bit_array] Create new package.
2021-12-28 15:51:45 +01:00
Jeroen van Rijn 53e30e4621 [core:container/bit_vector] Create new package.
A dynamic bit array, optionally allowing negative indices.
2021-12-28 15:38:12 +01:00
gingerBill dbf42d2469 make slice.as_ptr return [^]E 2021-12-28 14:16:27 +00:00
gingerBill 36c61aeacf Merge pull request #1350 from thePHTest/json-typo
Fix 'unmarsal' typo in core/encoding/json/unmarshal.odin
2021-12-28 14:11:27 +00:00
gingerBill 289b0422bd Merge pull request #1372 from ryuukk/patch-1
[WASM] Added missing zoffset parameters to some gl functions
2021-12-28 14:11:11 +00:00
gingerBill 78359f0c16 Merge pull request #1379 from weshardee/master
___$startup_runtime for MacOS
2021-12-28 14:09:42 +00:00
gingerBill 3f8c6a6745 Merge pull request #1396 from Platin21/feature/fix-matrix-return
Fixes Matrix/Float return on Arm64
2021-12-28 14:07:13 +00:00
gingerBill 5d653a9d8e Merge branch 'master' of https://github.com/odin-lang/Odin 2021-12-28 14:05:18 +00:00
gingerBill 7f61a90ea1 Remove core:container contents 2021-12-28 14:05:09 +00:00
Platin21 982ec1e58b Merge remote-tracking branch 'origin/master' into feature/fix-matrix-return 2021-12-27 22:11:08 +01:00
Platin21 86f831ddd1 This adds code which checks how big the return is and if it is to big returns the value via sret 2021-12-27 22:10:52 +01:00
Jeroen van Rijn 6f370fdbf2 Merge pull request #1394 from Tetralux/parse-allman-for
core:odin/parser: Fix parsing of Allman style braces in for loops
2021-12-25 20:24:30 +01:00
Tetralux a60667e900 core:odin/parser: Fix parsing of Allman style braces in for loops 2021-12-25 19:18:29 +00:00
Jeroen van Rijn 6889cb6fe2 Merge pull request #1393 from Tetralux/odin-parse-no-nil
core:odin/parser: Parse #no_nil on unions
2021-12-25 20:12:01 +01:00
Tetralux 9b2fe56d14 Parse #no_nil on unions 2021-12-25 18:58:08 +00:00
Andrea Piseri 5d80e24224 Add slice/scanner proc 2021-12-23 12:49:40 +01:00
Jeroen van Rijn eec61c3f6f Merge pull request #1388 from Yawning/feature/linux-aarch64
src: Add preliminary support for Linux AArch64
2021-12-23 04:17:42 +01:00
Yawning Angel dce120258f src: Add preliminary support for Linux AArch64
Tested via `tests/core`, on a Raspberry Pi 4 running the latest
64-bit Raspberry Pi OS image (LLVM 11).
2021-12-23 02:46:32 +00:00
gingerBill 5752a374ab Merge pull request #1386 from Platin21/feature/fix-arm64
Removes unneeded lookups / Adds sret to call site which fixes the mac…
2021-12-23 01:06:39 +00:00
Platin21 8dbeed8a9f Removes unneeded lookups / Adds sret to call site which fixes the mac bug 2021-12-23 01:59:31 +01:00
gingerBill 84d774c7b4 Merge pull request #1382 from Tetralux/rename-to-dynamic
Rename slice.to_dynamic to slice.clone_to_dynamic
2021-12-21 10:26:36 +00:00
Tetralux e2b36c4004 Rename slice.to_dynamic to slice.clone_to_dynamic 2021-12-21 02:17:24 +00:00
gingerBill 8453a6cbdb Merge pull request #1380 from Platin21/feature/llvm-version-check
Adds version check for Apple Silicon for LLVM Version
2021-12-19 21:15:54 +00:00
Platin21 3e465c7e84 Changes to required llvm version 13 as both 12 and 11 don't work correctly on macOS Apple Silicon 2021-12-19 21:51:51 +01:00
Wes Hardee 92ce7defb1 Merge branch 'master' of https://github.com/weshardee/Odin 2021-12-18 12:43:33 -06:00
Wes Hardee a48317deee use '___$startup_runtime' for MacOS
MacOS needs 3 underscores unlike the 2 needed by Linux.
2021-12-18 12:43:24 -06:00
CiD- ebdb3ab43a added notes about _unix_alloc 2021-12-17 12:04:05 -05:00
CiD- 29ca6ee420 add zeroing to new region from realloc 2021-12-17 10:41:49 -05:00
gingerBill 0548db4230 Disallow @(static) and @(thread_local) within defer statements 2021-12-17 11:06:17 +00:00
gingerBill aba6d2e52c Merge pull request #1374 from indiscible/fix-mathprod
fix math.prod
2021-12-16 18:34:10 +00:00
gilles 4ebdb6740e fix math.prod
accumulator was not initialized to one
2021-12-16 18:55:51 +01:00
ryuukk d0240b8981 [WASM] Added missing zoffset parameters to some gl functions 2021-12-15 06:12:26 +01:00
gingerBill 4423bc0706 Fix typo 2021-12-12 01:10:40 +00:00
gingerBill 8c72813b85 Merge pull request #1364 from RehkitzDev/fix-webgl-glue
Fix storeInt call in webgl glue code
2021-12-11 17:52:45 +00:00
gingerBill 08a081ed45 Improve debug symbol retention with -debug -opt:0 2021-12-11 17:42:58 +00:00
Rehkitzdev b7c78da1fb Fix storeInt call in webgl glue code 2021-12-11 18:38:32 +01:00
Jeroen van Rijn 3257454209 Merge pull request #1363 from Kelimion/big_math
[math/big] Rename `internal_int_shl_digit` to `_private_int_shl_leg`.
2021-12-11 15:31:43 +01:00
Jeroen van Rijn 938744b276 [math/big] Rename internal_int_shl_digit to _private_int_shl_leg.
Same for the SHR variant. These are pure implementation details to shift by a leg/word at a time.
Prevent accidental usage.
2021-12-11 15:22:24 +01:00
gingerBill 84b84d9f7d Fix rat_set_f64 2021-12-11 12:47:05 +00:00
gingerBill 85f8c8df91 Fix fields_proc in strings and bytes 2021-12-11 12:04:34 +00:00
gingerBill c889591333 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-12-11 12:02:33 +00:00
gingerBill e2f53ee107 Fix #1362 strings.index_any 2021-12-11 12:02:23 +00:00
Jeroen van Rijn c771ea9794 Merge pull request #1358 from Kelimion/big_math_fix
[math/big] Return 0, .Integer_Underflow if T = unsigned and bigint is negative.
2021-12-09 16:41:37 +01:00
gingerBill 94bad4d786 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-12-09 15:36:12 +00:00
gingerBill 1d7c9cf872 Make strconv more robust 2021-12-09 15:35:00 +00:00
gingerBill 1e17d5d86f Add utility procedures to get low values 2021-12-09 15:34:35 +00:00
gingerBill 1e9b30666f Minor style change 2021-12-09 15:34:17 +00:00
Jeroen van Rijn b2b79b86f0 [math/big] Return 0, .Integer_Underflow if trying to get a negative number to an unsigned int. 2021-12-09 16:31:54 +01:00
Jeroen van Rijn 3d85013aba Merge pull request #1357 from Kelimion/big_math_fix
[math/big] Fix int_set and int_get.
2021-12-09 16:22:09 +01:00
Jeroen van Rijn c94098c2ab [math/big] Fix int_set and int_get. 2021-12-09 16:14:04 +01:00
gingerBill 9d4fe90356 Fix bugs in big.Rat caused by typos 2021-12-07 17:35:41 +00:00
Jeroen van Rijn 6e61abc7d0 [xml] Initial optimization. 2021-12-06 12:04:59 +01:00
Phil H a7138b22a5 Fix 'unmarsal' typo 2021-12-05 19:04:14 -08:00
Jeroen van Rijn 7ec88d2430 [xml] Add option. 2021-12-05 21:06:33 +01:00
Jeroen van Rijn d7200f6144 Improve tests in general.
Less spammy core tests: They don't print PASSes now, only logs and failures.

`core:image` and `core:encoding/xml` tests also find their assets relative to `ODIN_ROOT` now.
2021-12-05 02:53:09 +01:00
Jeroen van Rijn d65d6edb0e [xml] Improve XML tests, test core:encoding/entity. 2021-12-05 02:52:23 +01:00
Jeroen van Rijn 3d72e80ccf [xml] Implement optional unboxing of CDATA and decoding of tag values. 2021-12-05 02:52:23 +01:00
Jeroen van Rijn 2dd67dba89 [core:encoding/entity] Add new package to decode &<entity>; entities.
Includes generator to generate a lookup for named entitiess.
2021-12-05 02:52:23 +01:00
Jeroen van Rijn 5807214406 [xml] Improvements. 2021-12-05 02:52:23 +01:00
Jeroen van Rijn 23baf56c87 [xml] Improve CDATA + comment handling in tag body. 2021-12-05 02:52:23 +01:00
Jeroen van Rijn beff90e1d1 [xml] Slight optimization.
About a 5% speed bump.

More rigorous optimization later.
2021-12-05 02:52:23 +01:00
Jeroen van Rijn ec63d0bbd2 [xml] Robustness improvement.
Can now parse  https://www.w3.org/2003/entities/2007xml/unicode.xml no problem.
2021-12-05 02:52:22 +01:00
Jeroen van Rijn 32eab04d66 [xml] Allow multi-line bodies w/o CDATA. Strip trailing whitespace. 2021-12-05 02:52:22 +01:00
Jeroen van Rijn 682783a2aa [xml] Tab indentation in debug printer. 2021-12-05 02:52:22 +01:00
Jeroen van Rijn 46a4927aca [xml] Use io.Writer for xml.print(doc). 2021-12-05 02:52:22 +01:00
Jeroen van Rijn 9b2e67df67 [xml] Small cleanup. 2021-12-05 02:52:22 +01:00
Jeroen van Rijn b5c828fe4e [xml] Initial implementation of core:encoding/xml.
A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).

Features:
		- Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage.
		- Simple to understand and use. Small.

Caveats:
		- We do NOT support HTML in this package, as that may or may not be valid XML.
		  If it works, great. If it doesn't, that's not considered a bug.

		- We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences.
		- <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options.

TODO:
- Optional CDATA unboxing.
- Optional `&gt;`, `&#32;`, `&#x20;` and other escape substitution in tag bodies.
- Test suite

MAYBE:
- XML writer?
- Serialize/deserialize Odin types?
2021-12-05 02:52:22 +01:00
gingerBill 6ce5608003 Correct odin doc default parameter value init_string generation 2021-12-03 11:46:54 +00:00
Jeroen van Rijn db42a2db47 Merge pull request #1347 from DanielGavin/parser-fix
Do not save comments when peeking tokens.
2021-12-02 23:05:24 +01:00
DanielGavin cecca96f3d Merge branch 'odin-lang:master' into parser-fix 2021-12-02 22:45:14 +01:00
Daniel Gavin f1a126e162 Do not save the comment when peeking. 2021-12-02 22:44:47 +01:00
gingerBill 9f0a30e36e Merge pull request #1337 from DanielGavin/parser-fix
Add Matrix_Type as literal type on "core:odin"
2021-11-28 10:38:37 +00:00
Daniel Gavin 517c8ff1dd Include Matrix_Type to the is_literal_type switch statement. 2021-11-28 02:14:25 +01:00
gingerBill 2b07afaf70 Add lb_build_addr on or_return and or_else for sanity's sake 2021-11-27 16:03:03 +00:00
gingerBill 6616882708 Correct reading from a console on Windows
e.g. `os.read(os.stdin, buf[:])`
2021-11-27 14:59:35 +00:00
gingerBill c9c197ba08 Add os.read_at_least and os_read_full utility procedures. 2021-11-27 14:57:49 +00:00
gingerBill 7876660d8c Add new utf16 procedures: decode, decode_to_utf8 2021-11-27 14:57:20 +00:00
gingerBill db9326f31d Merge pull request #1332 from odin-lang/nasm-support
NASM Support
2021-11-26 23:06:33 +00:00
gingerBill 27106dd9ae Allow .asm, .s, and .S as valid assembly file extensions 2021-11-26 22:25:07 +00:00
gingerBill 33dc12a61a Add supported check for .asm files 2021-11-26 14:46:03 +00:00
gingerBill ffd7ca57f1 Move nasm.exe to windows/nasm.exe, etc 2021-11-26 14:40:39 +00:00
Daniel Gavin a4ba91a554 Check for non inserted semicolon in *expect_closing_brace_of_field_list* 2021-11-25 18:47:58 +01:00
gingerBill 44897b5eac Merge pull request #1334 from jockus/allow-enum-any-int
Allow enums to pass #any_int checks
2021-11-25 11:31:04 +00:00
Joakim Hentula 8255481204 Allow enums to pass #any_int checks 2021-11-25 11:20:40 +00:00
gingerBill 1e453cf1d7 Merge pull request #1296 from kevinsjoberg/do-not-filter-tests-when-empty
Do not filter test procedures when filter is empty
2021-11-25 09:13:31 +00:00
gingerBill c34a331696 Add -extra-assembler-flags 2021-11-24 22:20:18 +00:00
Daniel Gavin cf390bf8b9 Recover from closing brace not found in field list 2021-11-24 21:20:46 +01:00
gingerBill 07ec93bfeb Add procs_windows_amd64.asm for use with -no-crt 2021-11-24 18:32:27 +00:00
gingerBill 994ee5a559 Allow for multiple .asm files 2021-11-24 17:57:31 +00:00
gingerBill 50057b0696 Add basic support for foreign import "foo.asm" on Windows with nasm.exe 2021-11-24 16:56:42 +00:00
gingerBill 00597127dd Add missing field skip_missing 2021-11-24 16:39:29 +00:00
gingerBill 70d4bc8573 Add nasm binaries 2021-11-24 16:36:34 +00:00
gingerBill bc775afccb Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-24 16:31:47 +00:00
gingerBill 504ea7deeb Fix update_untyped_expr_type for ternary if expressions with an untyped type 2021-11-24 16:31:37 +00:00
gingerBill 5e2280a787 Fix set_file_path_string and thread_safe_set_ast_file_from_id 2021-11-24 16:20:01 +00:00
gingerBill 84e03421d3 Merge pull request #1312 from DYSEQTA/master
Improve compiler help output with regard to command specific help.
2021-11-24 15:49:49 +00:00
DYSEQTA 0a87ffe0e6 Merge branch 'odin-lang:master' into master 2021-11-24 12:07:14 +11:00
DYSEQTA e5f961b48f Removed '--help' from help string as per request. 2021-11-24 11:10:40 +11:00
gingerBill 5db505c42f Merge pull request #1277 from Yawning/feature/modern-crypto
core/crypto: Add some "modern" primitives
2021-11-23 17:54:03 +00:00
gingerBill 275241f9b4 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-23 11:43:38 +00:00
gingerBill 9246e89c4a Fix #1328 2021-11-23 11:43:32 +00:00
gingerBill b56964e465 Merge pull request #1315 from SrMordred/patch-2
GetMouseDelta
2021-11-23 11:30:54 +00:00
gingerBill 2e89585c8c Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-23 10:59:50 +00:00
gingerBill e230b7110c Merge pull request #1327 from graphitemaster/fix-path-join-leak
fix memory leak in path.join
2021-11-22 15:34:30 +00:00
Dale Weiler a55f0cfb63 fix memory leak in path.join 2021-11-22 10:25:54 -05:00
gingerBill de435c9318 Remove unneeded semicolons from vendor:OpenGL 2021-11-21 14:52:40 +00:00
gingerBill f40f12d480 Minor cleanup to math constants 2021-11-21 14:06:32 +00:00
gingerBill 8a2c829e07 Patch odin doc binary format 2021-11-21 14:06:15 +00:00
gingerBill 42b9ce636f Remove #force_inline from all wrappers 2021-11-21 13:59:28 +00:00
gingerBill ca6951d05e Add MessageDecompose; Update the static library 2021-11-20 20:20:12 +00:00
gingerBill 446f1f6183 Correct foreign imports for portmidi on Windows 2021-11-20 19:27:34 +00:00
gingerBill d424c84bf9 Merge pull request #1322 from Gaunsessa/master
Add darwin support for glfw and re-add ln for js.
2021-11-20 12:22:38 +00:00
Gus 56d2bbc5b9 Added back ln for js 2021-11-20 20:03:54 +11:00
Gus 2c7bf87998 Added darwin support 2021-11-20 20:02:21 +11:00
gingerBill daebaa8b50 Fix #1319 2021-11-19 15:43:13 +00:00
gingerBill 9320a31f4d Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-19 12:26:19 +00:00
gingerBill 3e04b45106 Allow cast from float to complex 2021-11-19 12:26:10 +00:00
gingerBill acd5878d66 Merge pull request #1316 from Skytrias/master
add `builtin.` in slice.swap_between
2021-11-18 23:48:43 +00:00
Michael Kutowski 4439d59105 add builtin. 2021-11-19 00:24:56 +01:00
gingerBill 12c1291805 Add optional seed parameters to all hashes 2021-11-18 16:14:33 +00:00
Patric Dexheimer 61bc963e92 GetMouseDelta 2021-11-17 19:03:01 -03:00
gingerBill ae59f214ee @(tag=<string>) - dummy attribute for tooling 2021-11-17 21:32:33 +00:00
Yawning Angel 6bafa21bee crypto: Add rand_bytes
This adds `rand_bytes(dst: []byte)` which fills the destination buffer
with entropy from the cryptographic random number generator.  This takes
the "simple is best" approach and just directly returns the OS CSPRNG
output instead of doing anything fancy (a la OpenBSD's arc4random).
2021-11-17 14:00:00 +00:00
Yawning Angel 61c581baeb core/sys/unix: Add syscalls_linux.odin
Linux is in the unfortunate situation where the system call number is
architecture specific.  This consolidates the system call number
definitions in a single location, adds some wrappers, and hopefully
fixes the existing non-portable invocations of the syscall intrinsic.
2021-11-17 14:00:00 +00:00
Yawning Angel 6c4c9aef61 core/crypto: Add chacha20poly1305
This package implements the chacha20poly1305 AEAD construct as specified
in RFC 8439.
2021-11-17 13:59:53 +00:00
Yawning Angel 7bed317636 core/crypto: Add chacha20
This package implements the ChaCha20 stream cipher as specified in
RFC 8439, and the somewhat non-standard XChaCha20 variant that supports
a 192-bit nonce.

While an IETF draft for XChaCha20 standardization exists,
implementations that pre-date the draft use a 64-bit counter, instead of
the IETF-style 32-bit one.  This implementation opts for the latter as
compatibility with libsodium is more important than compatibility with
an expired IETF draft.
2021-11-17 13:59:53 +00:00
Yawning Angel 4647081f49 core/crypto/poly1305: Triple performance on amd64 with -o:speed 2021-11-17 13:59:53 +00:00
Yawning Angel 64db286582 core/crypto: Add poly1305
This package implements the Poly1305 MAC algorithm as specified in RFC
8439, using routines taked from fiat-crypto and poly1305-donna.
2021-11-17 13:59:53 +00:00
Yawning Angel 1a7a6a9116 core/crypto: Add x25519
This package implements the X25519 key agreement scheme as specified in
RFC 7748, using routines taken from fiat-crypto and Monocypher.
2021-11-17 13:59:53 +00:00
Yawning Angel d1e76ee4f2 core/crypto: Add constant-time memory comparison routines
Using a constant-time comparison is required when comparing things like
MACs, password digests, and etc to avoid exposing sensitive data via
trivial timing attacks.

These routines could also live under core:mem, but they are somewhat
specialized, and are likely only useful for cryptographic applications.
2021-11-17 13:59:53 +00:00
gingerBill 9be0d18e5d Correct x in ptr logic 2021-11-17 11:02:11 +00:00
gingerBill e877525073 Keep -vet happy for -no-crt and wasm targets 2021-11-17 10:40:55 +00:00
gingerBill f09638318f Add support for darwin to core:c/libc 2021-11-16 21:19:08 +00:00
gingerBill bb7703fcec Improve ptr_map_hash_key 2021-11-16 16:08:20 +00:00
gingerBill 1b28226a67 Add math.lgamma based off FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c 2021-11-16 15:32:32 +00:00
gingerBill 2b546a598c Add math.signbit; Add math.gamma based on http://netlib.sandia.gov/cephes/cprob/gamma.c 2021-11-16 15:23:19 +00:00
gingerBill b530ca9a5e Add math.nextafter 2021-11-16 15:12:01 +00:00
gingerBill d232796149 Fix typo 2021-11-16 15:09:47 +00:00
gingerBill e721f26a76 Implement ln based off FreeBSD's /usr/src/lib/msun/src/e_log.c 2021-11-16 15:05:04 +00:00
gingerBill 91408cb21f Implement atanh based on FreeBSD's /usr/src/lib/msun/src/e_atanh.c 2021-11-16 14:58:59 +00:00
gingerBill eb8b0d7a03 Add log1p, erf, erfc, ilogb logb (implemented based of FreeBSD's) 2021-11-16 14:54:57 +00:00
gingerBill 880af47ae7 Rename math_js.odin to math_basic_js.odin 2021-11-16 14:26:04 +00:00
gingerBill 91949b0992 Implement math.sqrt with intrinsics.sqrt 2021-11-16 14:11:20 +00:00
gingerBill 6a101e69a2 Implement ldexp and frexp in native Odin 2021-11-16 14:04:49 +00:00
cybermancer 1823b0cead Improve compiler help output with regard to command specific help. 2021-11-16 15:15:21 +11:00
gingerBill 1ec0b79345 Allow both -help and --help if passed as init_filename 2021-11-15 22:10:31 +00:00
gingerBill e814a3693f Improve usage of file_id 2021-11-15 17:26:01 +00:00
gingerBill f55fc4cd08 Add complex32 and quaternion64 for the 16-bit float types to fmt 2021-11-15 17:25:29 +00:00
gingerBill f47311f2f6 Remove scope field from Ast 2021-11-14 15:22:40 +00:00
gingerBill 3f038428a7 Begin minimizing Ast size 2021-11-14 15:12:37 +00:00
gingerBill b9701340b8 Add linalg.matrix4_look_at_from_fru 2021-11-13 19:15:37 +00:00
gingerBill 82110bf487 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-13 19:07:27 +00:00
gingerBill a75dc9d86d Fix minor issue with unmarshal for booleans 2021-11-13 19:07:16 +00:00
gingerBill bfa23f1352 Merge pull request #1308 from Yawning/fix/amd64-syscalls
src: Fix the syscall intrinsic code generation for Linux and Windows
2021-11-13 18:54:12 +00:00
Yawning Angel c430a82721 src: Fix the syscall intrinsic code generation for Linux and Windows
The old assembly generated for the syscall intrinsic did not specify
clobber constraints.  This adds RCX and R11 (that are clobbered by
the instruction itself), and memory (that is clobbered by some
system calls) to the assembly constraints.

Note: This is still incorrect on FreeBSD, which clobbers more registers
and uses the carry flag instead of -errno in rax to indicate an error.
2021-11-13 09:53:20 +00:00
Jeroen van Rijn cc316a473e Merge pull request #1299 from Kelimion/vendor-glfw-test
[vendor:glfw] Add test.
2021-11-10 19:24:55 +01:00
Jeroen van Rijn c213274607 [vendor:glfw] Add test. 2021-11-10 19:15:10 +01:00
Jeroen van Rijn c4a2580dfd Merge pull request #1290 from wjlroe/fix-glfw-on-windows
Fix path to static GLFW lib on Windows
2021-11-10 18:41:30 +01:00
Jeroen van Rijn 8a547b5922 Merge pull request #1298 from CarwynNelson/ws32-add-socket
Add socket() function to windows ws32 bindings
2021-11-10 17:23:59 +01:00
Carwyn Nelson c67c0789eb Add socket() function to windows ws32 bindings
It looks like this was missing from the winsock bindings. Odin contains
WSASocketW which I assume would also work for obtaining a socket, but
socket() is distinct and is what I was using, so I assume others will
want it too.
2021-11-10 15:55:50 +00:00
Jeroen van Rijn cefe312ba1 Merge pull request #1297 from CarwynNelson/patch-1
Fix the windows binding for getaddrinfo
2021-11-10 16:22:56 +01:00
Carwyn Nelson d8b1523161 Fix the windows binding for getaddrinfo
getaddrinfo should take a double pointer to ADDRINFOA instead of a single pointer. If you call the binding in its current state you will not get back a valid ADDRINFOA struct.

I have also changed the `node` and `service` params to be cstring to avoid having to do `transmute(u8) value`.
2021-11-10 15:15:40 +00:00
Kevin Sjöberg 61b02adc50 Do not filter test procedures when filter is empty
If `build_context.test_names` is empty, we do not need to perform any
filtering.
2021-11-10 15:49:23 +01:00
Jeroen van Rijn 989ddbd688 Merge pull request #1295 from zhibog/master
Add tests to Linux and Mac and add vendor tests
2021-11-10 15:34:29 +01:00
zhibog 96b670af49 Fix package name again 2021-11-10 15:31:29 +01:00
zhibog 359e02bad7 Fix botan lib name for apt 2021-11-10 15:26:26 +01:00
zhibog 8aadcacc0b Add tests to Linux and Mac and add vendor tests 2021-11-10 15:22:12 +01:00
Jeroen van Rijn 615efc7c86 Merge pull request #1294 from Kelimion/fix_dir_walk
Fix os.walk for UNC paths.
2021-11-10 15:09:22 +01:00
Jeroen van Rijn dd88104a81 Fix os.walk for UNC paths. 2021-11-10 14:59:54 +01:00
gingerBill 5cb23725ae Merge pull request #1289 from Kelimion/timings-export
Add functionality to export build timings.
2021-11-10 12:06:36 +00:00
Jeroen van Rijn 8c5c45a04c [timings-export] Style fixes. 2021-11-10 12:23:46 +01:00
gingerBill 4a552e6326 Merge pull request #1286 from DanielGavin/parser-fix
Add Any_Int as allowed flag in field signatures.
2021-11-10 10:59:53 +00:00
gingerBill 1f0758708f Merge pull request #1293 from kevinsjoberg/fix-test-filtering
Postpone checking test procedures
2021-11-10 10:52:01 +00:00
Kevin Sjöberg b8dec4268d Postpone checking test procedures
The dependency set need to be generated before we check the testing
procedures. Otherwise `checker->info.testing_procedures` will be empty
and thus no filtering is taking place.
2021-11-10 10:26:17 +01:00
gingerBill fc920a630f Merge pull request #1288 from odin-lang/target-js_wasm32
Target `js_wasm32` with `vendor:wasm/WebGL`
2021-11-09 23:15:42 +00:00
Jeroen van Rijn ffeac8895d Merge pull request #1291 from zhibog/master
Add Botan crypto lib as a vendor library
2021-11-09 23:59:14 +01:00
zhibog cef9632607 Add Botan crypto lib as a vendor library 2021-11-09 23:49:17 +01:00
gingerBill 76054dddb7 Revert build.bat 2021-11-09 22:11:18 +00:00
Jeroen van Rijn 9dc8753a14 [timings-export] Improve help messages
Also make `clang` happy as concerns the build settings switch/case.
2021-11-09 22:52:26 +01:00
William Roe a805d9a721 Fix path to static GLFW lib on Windows 2021-11-09 20:10:34 +00:00
Jeroen van Rijn 6c306f7633 Fix Linux warnings. 2021-11-09 20:31:22 +01:00
Jeroen van Rijn 05a86d5296 [timings-export] Implement JSON + CSV timngs export. 2021-11-09 19:57:55 +01:00
Jeroen van Rijn 9422fd311f [timings-export] Add -export-timings:format + -export-timings-file:filename. 2021-11-09 19:51:27 +01:00
gingerBill 80360f3f51 Add vendor packages for the js_wasm32 target 2021-11-09 18:26:42 +00:00
gingerBill 321d93bff1 Merge branch 'master' into target-js_wasm32 2021-11-09 18:06:19 +00:00
gingerBill 600d19c51b General catch-all for llvm debug types 2021-11-09 18:04:31 +00:00
gingerBill ed933bca19 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-09 16:36:01 +00:00
gingerBill a9ea590d24 Add dummy time_freestanding.odin 2021-11-09 16:35:50 +00:00
Jeroen van Rijn 275d39b59b Merge pull request #1287 from zhibog/master
Removed context switching system from the crypto library to simplify …
2021-11-09 16:57:59 +01:00
zhibog c24454ae70 Removed context switching system from the crypto library to simplify the code 2021-11-09 16:50:13 +01:00
DanielGavin fbc38c78eb Merge branch 'odin-lang:master' into parser-fix 2021-11-09 14:30:34 +01:00
Daniel Gavin b0db90de96 Add Any_Int as allowed flag in field signatures. 2021-11-09 14:29:53 +01:00
Jeroen van Rijn eb96f9677e Merge pull request #1285 from Kelimion/vet
[core:os/os2] Keep -vet happy.
2021-11-09 14:12:04 +01:00
Jeroen van Rijn 0a3b75c5f5 [core:os/os2] Keep -vet happy. 2021-11-09 14:06:14 +01:00
gingerBill 50562440bf Correct wasm-ld path for non-Windows platforms 2021-11-09 08:09:56 +00:00
gingerBill ce90c3c9ee Merge pull request #1284 from odin-lang/vendor-raylib-4.0
raylib 4.0
2021-11-09 08:05:48 +00:00
gingerBill d4bdcd55e1 Add Modified README.md 2021-11-08 16:25:51 +00:00
gingerBill 3f90faf0c9 Update vendor:raylib version 4.0 2021-11-08 15:57:55 +00:00
gingerBill 3d35c5ceb1 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-08 12:16:04 +00:00
gingerBill a674e842d0 Improve matrix indices to offset logic 2021-11-08 12:15:57 +00:00
gingerBill 23f0fbc376 Improve matrix->matrix casting implementation 2021-11-08 11:40:41 +00:00
gingerBill c63f4d68c8 Add math_js.odin specific calls (that just wrap the f64 procedures) 2021-11-07 20:06:05 +00:00
gingerBill 518460af66 Begin work in semi-standardized js_wasm32 target 2021-11-07 19:56:01 +00:00
gingerBill 39f652de47 Merge pull request #1280 from zhibog/master
Fix order of operations to make it correct and work with -o:speed flag
2021-11-07 18:08:33 +00:00
zhibog 483afe462b Fix order of operations to make it correct and work with -o:speed flaf 2021-11-07 18:53:30 +01:00
gingerBill 1296fabe2c Fix typos 2021-11-07 16:20:04 +00:00
gingerBill dc2edd3e79 Improve support for freestanding_wasm32 2021-11-07 16:19:27 +00:00
gingerBill e9c903f1ea Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-07 14:16:13 +00:00
gingerBill 83be954efd Minor spelling change 2021-11-07 14:16:05 +00:00
Jeroen van Rijn f84bdee1ba Merge pull request #1279 from DanielGavin/fix-json
Add json encoding test + fix enum not being set on success.
2021-11-07 14:47:35 +01:00
Daniel Gavin 5b074ceee5 Add json encoding test + fix enum not being set on success. 2021-11-07 14:35:52 +01:00
gingerBill 40eed29527 Remove LLVMAddDeadStoreEliminationPass pass 2021-11-06 18:11:29 +00:00
gingerBill 3d3785a7f1 Remove many LLVM optimization passes which were causes UB due to them assuming C-like behaviour incompatible with Odin 2021-11-06 17:23:33 +00:00
gingerBill 5df15b5724 Completely ignore LLVM_ADD_CONSTANT_VALUE_PASS LLVM >= 12 2021-11-06 16:29:53 +00:00
gingerBill ee259e4229 Merge pull request #1273 from odin-lang/compiler-map-improvements
Compiler Map Improvements
2021-11-05 18:12:40 +00:00
gingerBill 36985f8da0 Simplification to ptr_map_hash_key 2021-11-05 18:04:18 +00:00
gingerBill eb0faf9602 Unify hash logic for PtrSet 2021-11-05 17:58:11 +00:00
gingerBill 899cc71990 Improve ptr_map_hash_key 2021-11-05 17:55:09 +00:00
gingerBill 7be18b4a80 Be more correct with MapIndex usage 2021-11-05 17:36:00 +00:00
gingerBill 0c9bb9d920 Clean up logic 2021-11-05 17:32:17 +00:00
gingerBill 26e3daf5ad Unify MapFindResult types 2021-11-05 17:24:19 +00:00
gingerBill 0af69f8cda Remove map.cpp code 2021-11-05 17:16:37 +00:00
gingerBill 86e26c9a44 Remove dead code 2021-11-05 17:13:26 +00:00
gingerBill 541beb615b Move more things to PtrMap 2021-11-05 17:13:07 +00:00
gingerBill 6646348e1a Increase usage of PtrMap 2021-11-05 17:03:02 +00:00
gingerBill c38d6dc959 Remove HashKey usage for PtrMap calls 2021-11-05 16:46:09 +00:00
gingerBill 924faa58b4 Correct map_remove(PtrMap) 2021-11-05 16:45:27 +00:00
gingerBill 6be104e521 Make llvm backend code use PtrMap; remove dead code 2021-11-05 16:43:53 +00:00
gingerBill e95204908a Add PtrMap, begin working change Map to PtrMap where possible 2021-11-05 16:34:37 +00:00
gingerBill e963fc4d6a Change map index types to u32 from isize 2021-11-05 12:51:28 +00:00
gingerBill 1a75a71403 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-05 12:44:08 +00:00
gingerBill 439fc86740 Improve performance of the compiler hash table types and unify behaviour 2021-11-05 12:42:19 +00:00
gingerBill 0010e882a7 Make PtrSet match Map 2021-11-05 12:11:50 +00:00
gingerBill a022f18015 Reorganize code 2021-11-05 12:11:33 +00:00
Jeroen van Rijn cee9561259 Merge pull request #1271 from hdooley/master
don't try to use __cpuid() on arm64
2021-11-05 10:45:28 +01:00
Henry Dooley 3d0cd6f0dc don't try to use __cpuid() on arm64 2021-11-04 18:54:15 -07:00
gingerBill adb5928767 Change to RUNTIME_LINKAGE definition 2021-11-04 20:21:51 +00:00
gingerBill 23c74bc67b Update all_main.odin to include core:math/linalg/hlsl 2021-11-04 19:30:46 +00:00
gingerBill a22120fe94 Reorganize code 2021-11-04 17:38:58 +00:00
gingerBill ae25eaf10c Correct foreign import library usage 2021-11-04 17:25:37 +00:00
gingerBill adcfca966e Use Rtl*Memory procedures with -no-crt on Windows 2021-11-04 17:24:28 +00:00
gingerBill d8e34bd9b7 Add core:math/linalg/hlsl 2021-11-04 17:08:59 +00:00
gingerBill 68046d0c08 Allow casting between matrix types of different element types 2021-11-04 16:50:59 +00:00
gingerBill bc2bf1caeb Add #load_hash(<filepath>, <string-hash-kind>) 2021-11-04 16:29:41 +00:00
gingerBill d551144841 Add inverse for dmatN types 2021-11-04 16:09:19 +00:00
gingerBill 84540d7aa2 Add smoothstep 2021-11-04 15:57:27 +00:00
gingerBill 57eedfc4f4 Fix lb_emit_array_epi for matrix types 2021-11-04 15:01:31 +00:00
gingerBill 2718ade2bc Add core:math/linalg/glsl to all_main.odin 2021-11-04 14:56:16 +00:00
gingerBill 95f36d4fa5 Minor reorganization 2021-11-04 14:54:55 +00:00
gingerBill 3accf4048e Add f64 variants of all types and procedures 2021-11-04 14:52:03 +00:00
gingerBill eb05879148 Add more comments 2021-11-04 14:25:34 +00:00
gingerBill a882118c56 Add comments 2021-11-04 14:20:47 +00:00
gingerBill 57d15ac6e7 Remove unneeded suffixes 2021-11-04 14:11:34 +00:00
gingerBill e3cfdf6982 Remove build tag 2021-11-04 14:11:04 +00:00
gingerBill 017fe10762 core:math/linalg/glsl - GLSL-like mathematics types and operations 2021-11-04 14:09:12 +00:00
gingerBill 7bb7a741c6 Make math procedure contextless; Add asinh, acosh, atanh 2021-11-04 14:07:05 +00:00
gingerBill 14351c5bf2 Simplify logic for procs.odin 2021-11-04 13:56:38 +00:00
gingerBill 7ef3c87dbb Change RUNTIME_LINKAGE requirements 2021-11-04 13:52:53 +00:00
gingerBill b2a2aa15c2 Add ODIN_BUILD_MODE 2021-11-04 12:49:39 +00:00
gingerBill 1ec2f8d537 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-04 12:40:55 +00:00
gingerBill 6ded538546 @(linkage=<string>) for procedures and variables; @(require) for procedures; package runtime linkage improvements; Subsequence improvements to lb_run_remove_unused_function_pass 2021-11-04 12:40:50 +00:00
Jeroen van Rijn 0d1bc05419 Update issue templates 2021-11-04 12:37:24 +01:00
Jeroen van Rijn db2d7a4fdb Update issue templates 2021-11-04 12:36:48 +01:00
gingerBill 3fa7dabaa8 Correctly support -default-to-nil-allocator for all platforms 2021-11-04 11:03:21 +00:00
gingerBill 1980f32bd6 Correct demo.odin 2021-11-04 00:50:48 +00:00
gingerBill 9ab71ca0da Add ODIN_NO_CRT global constant 2021-11-04 00:50:28 +00:00
gingerBill 3d06dddb72 Allow casting from floats to quaternions 2021-11-03 12:45:19 +00:00
gingerBill 9896205a06 Make runtime builtin matrix procedures contextless 2021-11-03 12:44:34 +00:00
gingerBill 8a626ef564 Minor comments about matrix printing 2021-11-03 11:34:47 +00:00
gingerBill 8429943569 Represent matrices in fmt as expected 2021-11-03 11:27:21 +00:00
gingerBill edd12d505d Correct fmt for matrices 2021-11-03 11:20:04 +00:00
gingerBill 69f978f22b Correct lb_emit_matrix_flatten 2021-11-03 11:07:35 +00:00
gingerBill 229c98309e Correct assertion usage 2021-11-03 11:02:47 +00:00
Jeroen van Rijn c2665462e5 Merge pull request #1270 from Kelimion/fix_1268
Fix #1268.
2021-11-03 11:41:32 +01:00
Jeroen van Rijn 73648bb2d8 Fix #1268.
Error message for enumerated arrays going out of bounds was not yet updated for the Enum change.
2021-11-03 11:36:24 +01:00
Jeroen van Rijn ba0daaa706 Merge pull request #1269 from Kelimion/enum_array_bug
Fix error message.
2021-11-03 11:06:04 +01:00
Jeroen van Rijn dcc5697a48 Fix error message. 2021-11-03 11:01:18 +01:00
gingerBill c20230509f Correct index to offset calculation for matrix compound literals 2021-11-02 23:56:19 +00:00
gingerBill f03e0bee73 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-02 12:54:29 +00:00
gingerBill c5cd97dd89 Improve wasm-import semantics to allow procedures from different import paths 2021-11-02 12:54:23 +00:00
Jeroen van Rijn c09d3e7bf4 Merge pull request #1265 from Kelimion/bug_report
`odin report` add Windows 10 Education Edition.
2021-11-02 02:21:01 +01:00
Jeroen van Rijn 46a394815c odin report add Windows 10 Education Edition. 2021-11-02 02:20:43 +01:00
gingerBill a4b68b93f2 Modify ABI for the wasm32 2021-11-01 23:18:39 +00:00
gingerBill e2e9b5d3b0 Remove comments 2021-11-01 23:04:00 +00:00
gingerBill b01e0fbbc2 Correct typo in soa data type debug information generation 2021-11-01 23:00:42 +00:00
Jeroen van Rijn 4f0a3eec24 Merge pull request #1263 from Kelimion/ci_build_debug
Don't run demo's `soa_struct` when under -debug.
2021-11-01 17:59:24 +01:00
Jeroen van Rijn 2a0311797c Don't run demo's soa_struct when under -debug. 2021-11-01 17:57:35 +01:00
Jeroen van Rijn 46e2b4e936 Merge pull request #1262 from Kelimion/ci_build_debug
CI: Run demo with debug info.
2021-11-01 17:45:02 +01:00
Jeroen van Rijn 96ba8f35d4 CI: Run demo with debug info. 2021-11-01 17:44:05 +01:00
gingerBill 9a5ddc5218 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-11-01 16:39:07 +00:00
gingerBill 0b4cbcf409 Correct debug info for matrix type 2021-11-01 16:39:02 +00:00
Jeroen van Rijn d0cd3a7415 Merge pull request #1261 from Kelimion/bug_report
Add Windows 10 Home Core detection.
2021-11-01 14:47:18 +01:00
Jeroen van Rijn 3a167e3a75 Add Windows 10 Home Core detection. 2021-11-01 14:46:59 +01:00
Jeroen van Rijn c9e21907ea Merge pull request #1259 from Kelimion/load_or
Fix (#1258): #load and #load_or segfault when given no params.
2021-11-01 10:47:59 +01:00
Jeroen van Rijn a422d0455e Fix (#1258): #load and #load_or segfault when given no params.
Fixes #1258.
2021-11-01 10:42:57 +01:00
gingerBill 0bc3652fc7 Merge pull request #1256 from Yawning/feature/volatile-memset
Add a way to securely scrub memory
2021-10-31 23:32:46 +00:00
Yawning Angel 672fc9fc4d core/mem: Add zero_explicit
This call is intended to provide the ability to securely scrub memory
without compiler interference, in a similar manner to explicit_bzero,
memset_s, SecureZeroMemory.

The approach taken is a volatile memset followed by a seqentially
consistent memory fence, to prevent the call from being optimized away
by DSE, and from being reordered.  An identical approach is currently
being used by the zeroize Rust crate, and is effective in practice.

LLVM IR output:
```
; Function Attrs: nounwind
define internal i8* @mem.zero_explicit(i8* %0, i64 %1) #0 {
decls:
  call void @llvm.memset.p0i8.i64(i8* %0, i8 0, i64 %1, i1 true)
  fence seq_cst
  ret i8* %0
}
```
2021-10-31 22:57:13 +00:00
Yawning Angel 796a0c3968 core/intrinsics: Add mem_zero_volatile 2021-10-31 21:37:22 +00:00
Yawning Angel ff36bd3d85 build: Support the Fedora LLVM 11 package
Fedora is on LLVM 12, and the backward compatibility package has a
non-standard name for llvm-config.
2021-10-31 20:23:03 +00:00
gingerBill 141299eb02 Change the behaviour change is for when a bit_set of range/enum and the underlying type has been specified
* If the lower bound is greater than zero, it will become zero (thus removing the compatification)
* If the lower bound is negative, it is an error

This means that an integer value N, maps directly to the N-th bit.

Example
```
foo :: enum u8 {
    a = 2,
    b = 3,
    c = 4,
}

set0: bit_set[foo]
set0 += {.a, .b}
// internally set0 == 1<<(2-2) | 1<<(3-2)

set1: bit_set[foo; u32]
set1 += {.a, .b}
// internally set1 == 1<<(2-0) | 1<<(3-0)
```
2021-10-31 19:39:01 +00:00
gingerBill efe05b3e13 Merge pull request #1252 from Kelimion/bug-report
Add new `odin report` command.
2021-10-31 19:19:56 +00:00
gingerBill b1de429d2c Merge pull request #1255 from odin-lang/wasi-wasm
`wasi_wasm32` support
2021-10-31 19:19:48 +00:00
gingerBill 5f51337a01 Add procs for wasm32 2021-10-31 19:00:01 +00:00
gingerBill fca7142a3c Correct _start export for wasm* targets 2021-10-31 16:31:20 +00:00
gingerBill bfa33bf5d3 Disable wasm64 2021-10-31 15:48:56 +00:00
gingerBill 235dae552a Ignore -use-separate-modules when targeting wasm32/wasm64 2021-10-31 15:35:09 +00:00
gingerBill a36c1ad406 Add default_allocators_wasi.odin 2021-10-31 15:28:51 +00:00
gingerBill 32506a34ff Separate out the ABI for wasm32 from 386 2021-10-31 15:23:39 +00:00
gingerBill 3224d04df8 Stub out os.open for wasi 2021-10-31 15:22:54 +00:00
gingerBill c13c30b466 Update wasi to use string and slice types 2021-10-31 15:21:39 +00:00
gingerBill 3de1719c17 Merge pull request #1254 from awwdev/master
remove prefix from Mix_LoadWAV
2021-10-31 15:01:44 +00:00
gingerBill 0c1675c8b0 Correct string usage 2021-10-31 15:01:13 +00:00
André 3d89c6b35d remove prefix from Mix_LoadWAV 2021-10-31 15:45:29 +01:00
gingerBill 22982586f1 Add basic support for wasi in package os 2021-10-31 13:45:00 +00:00
gingerBill 0d2c8dfeec Separate os-specific things to separate file 2021-10-31 13:44:21 +00:00
gingerBill 305e965bcb Add os_specific_wasi.odin 2021-10-31 13:08:19 +00:00
gingerBill 906c7ef0fc Correct wasi linking 2021-10-31 13:04:28 +00:00
Jeroen van Rijn 2a7937e2ba Add odin report command to help with bug reports.
Add new Odin command, `odin report`, which prints information helpful to resolving or reporting a bug.

```
W:\Odin> odin report

Where to find more information and get into contact when you encounter a bug:

	Website: https://odin-lang.org
	GitHub:  https://github.com/odin-lang/Odin/issues

Useful information to add to a bug report:

	Odin: dev-2021-10:256bebfe
	OS:   Windows 10 Professional (version: 20H2), build 19042.1266
	CPU:  AMD Ryzen 7 1800X Eight-Core Processor
	RAM:  65469 MiB

W:\Odin>

TODO:
- CPU name on ARM/ARM64
```
2021-10-31 13:48:13 +01:00
gingerBill 2a5b8f53fe Add memmove and memset support for wasm 2021-10-31 12:47:50 +00:00
gingerBill c6e08b059b Move sys/wasi to sys/wasm/wasi 2021-10-31 12:30:10 +00:00
gingerBill 9a5216921c Add wasi_wasm32 2021-10-31 01:08:17 +00:00
gingerBill 8a2078aa90 Add core:sys/wasi 2021-10-31 01:06:27 +00:00
gingerBill 841a96691b Attempt to get wasm64 compiling with the correct features enabled 2021-10-31 00:37:37 +01:00
gingerBill 8ef6f9dd7b Compile wasm64; Add lb_run_remove_unused_function_pass 2021-10-31 00:11:38 +01:00
gingerBill 5bc8a491a7 Begin work on supporting wasm64; Correct wasm32 compilation behaviour 2021-10-30 23:24:34 +01:00
gingerBill 87952fdb8e big.Rat (Experimental) 2021-10-29 12:40:54 +01:00
gingerBill c474e137ac Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-29 00:13:28 +01:00
gingerBill 7b8b2f042c Add debug type information for matrix 2021-10-29 00:13:22 +01:00
Jeroen van Rijn 729e721b40 Merge pull request #1203 from thePHTest/stopwatch
Add a stopwatch to time.odin
2021-10-28 23:28:22 +02:00
Phil H e4ce017183 better naming conventions for stopwatch procedures + fields 2021-10-28 14:08:21 -07:00
Phil bbccf9ddbf Add clock overloads for Duration and Stopwatch 2021-10-28 14:08:21 -07:00
Phil a8425cfb47 Add a stopwatch to time.odin 2021-10-28 14:08:21 -07:00
gingerBill ef29ffeb21 Correct llvm_vector_shuffle_reduction 2021-10-28 15:09:20 +01:00
gingerBill 3794d2417d Write a log(n) fallback for llvm_vector_reduce_add
This may be what LLVM does at any rate
2021-10-28 15:01:13 +01:00
gingerBill 70793236ab Support llvm_vector_reduce_add if the LLVM intrinsic is not supported 2021-10-28 00:57:10 +01:00
gingerBill 0a1ef1e59d Improve comment 2021-10-28 00:50:03 +01:00
gingerBill 44a43eae10 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-28 00:49:14 +01:00
gingerBill 5b7f273165 Add matrix_type to demo.odin 2021-10-28 00:49:09 +01:00
gingerBill fa07e45eda Merge pull request #1249 from Yawning/feature/math-bits-improvements
core:math/bits: Improve add/sub/mul_u64
2021-10-28 00:19:57 +01:00
gingerBill 90d587df13 Support matrix type in core:odin 2021-10-27 23:49:37 +01:00
gingerBill 793a6479ef Fix typo 2021-10-27 23:37:04 +01:00
gingerBill 47bef7a557 Update doc-format 2021-10-27 23:34:56 +01:00
gingerBill 208ba2c116 Comment clean up 2021-10-27 23:30:12 +01:00
gingerBill 42a8ac7096 Add support for matrix type in core:odin/doc-format 2021-10-27 23:26:39 +01:00
gingerBill ccab715bbc Add support for matrix type in doc format 2021-10-27 23:26:17 +01:00
Yawning Angel ee724f183a core:math/bits: Improve add/sub/mul_u64
* `add_u32`/`add_u64`/`add_uint` are now constant time
 * `sub_u32`/`sub_u64`/`sub_uint` are now constant time
 * `mul_u64` now uses `u128`
2021-10-27 12:37:35 +00:00
gingerBill c4d2aae0ed Merge pull request #1245 from odin-lang/new-matrix-type
`matrix` type
2021-10-26 21:08:08 +01:00
gingerBill c722665c32 Merge pull request #1230 from jockus/master
Convert all vendor:OpenGL functions taking GLboolean to bool
2021-10-26 21:04:20 +01:00
gingerBill 8868bcf57a Merge pull request #1234 from Skytrias/master
fix strip-semicolon using original file handle size
2021-10-26 21:04:02 +01:00
gingerBill 9e754cb0f1 Add slice.swap_between 2021-10-26 20:22:39 +01:00
gingerBill 802df73183 Remove unneeded call 2021-10-26 14:47:59 +01:00
gingerBill 9331ebebcc Add #no_bounds_check to sorting procedures 2021-10-26 14:24:21 +01:00
gingerBill c64674c39e Remove unnecessary asserts 2021-10-26 13:38:48 +01:00
gingerBill 549a383cf0 Merge branch 'master' into new-matrix-type 2021-10-26 12:53:47 +01:00
gingerBill ce8ddd0c3f Add vendor:ENet to all_vendor.odin 2021-10-26 12:50:48 +01:00
gingerBill 98490454b6 Remove unneeded semicolons 2021-10-26 12:50:34 +01:00
gingerBill bb334007cf Merge pull request #1240 from graphitemaster/vendor-enet
vendor ENet
2021-10-26 12:49:14 +01:00
gingerBill 9522c42460 Change use of LLVMSizeOf to lb_sizeof 2021-10-26 12:17:39 +01:00
gingerBill d165de0d4d Move thread initialization variables in thread_unix.odin 2021-10-26 11:46:31 +01:00
gingerBill 5fb70c4c94 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-26 11:44:32 +01:00
gingerBill 72cc92dc5c Add llvm_get_inline_asm for future compatibility 2021-10-26 11:44:25 +01:00
gingerBill de0fbb0445 Merge pull request #1243 from ProkopRandacek/patch-1
glfw.WindowShouldClose should return a bool
2021-10-25 19:41:58 +01:00
gingerBill 12ebd422c6 Fix typos 2021-10-25 19:04:08 +01:00
gingerBill 7d715fe113 Add ODIN_LLVM_MINIMUM_VERSION_12 2021-10-25 16:05:22 +01:00
gingerBill 7ac156755b Reorder code 2021-10-25 15:36:00 +01:00
gingerBill 973ca6824c Rename hermitian_adjoint 2021-10-25 15:35:06 +01:00
gingerBill 9c7956be9e Minor changes to where conditions 2021-10-25 15:16:34 +01:00
gingerBill 4475454632 Improve core_builtin_matrix.odin 2021-10-25 14:59:43 +01:00
gingerBill f15825d2c6 Fix typo 2021-10-25 13:32:53 +01:00
gingerBill a440d8d812 Improve use of vector muladd operations 2021-10-25 13:10:56 +01:00
gingerBill aaaddd03a6 Improve internal procedures 2021-10-25 01:28:06 +01:00
gingerBill d62c701a43 Improve matrix code generation for all supported platforms
Through assembly optimization
2021-10-25 01:03:16 +01:00
gingerBill 79ad6f4564 Remove assert 2021-10-25 01:02:38 +01:00
gingerBill c60c7a7621 Add comments to Type_Info_Matrix 2021-10-25 00:47:12 +01:00
gingerBill 306bdf8869 Update alignment rules for matrix types as a compromise to keep zero padding 2021-10-25 00:46:50 +01:00
Dale Weiler 37d3a8a861 fixes for windows 2021-10-24 10:54:46 -04:00
gingerBill 7a29f6cff0 Merge branch 'master' into new-matrix-type 2021-10-24 12:36:34 +01:00
gingerBill c9e6862332 Add id to thread.Thread 2021-10-24 12:30:25 +01:00
Prokop Randacek b77e2f59ed The better option 2021-10-24 13:07:13 +02:00
Prokop Randáček cac8582de1 WindowShouldClose should return a bool 2021-10-24 12:52:54 +02:00
gingerBill b4df51e483 Merge branch 'master' into new-matrix-type 2021-10-23 19:24:47 +01:00
gingerBill 06f4762144 Allow parsing for [^]T{} to improve error messages 2021-10-23 19:22:08 +01:00
Dale Weiler 357d085ffb use multi pointer here, cstring was incorrect 2021-10-23 13:09:54 -04:00
gingerBill 2a50f9c8d4 Rename -ignore-lazy to -internal-ignore-lazy 2021-10-23 17:41:11 +01:00
gingerBill d54b708ba8 Unify memory_equal and string_eq 2021-10-23 17:18:40 +01:00
gingerBill fba20c9bd3 Improve runtime.string_eq 2021-10-23 17:10:30 +01:00
gingerBill 18ed444a63 Strip semicolons 2021-10-23 17:10:12 +01:00
gingerBill 2d6c43c260 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-23 16:52:50 +01:00
gingerBill 71932da7e3 Add intrinsics.unaligned_store intrinsics.unaligned_load 2021-10-23 16:52:43 +01:00
Dale Weiler a074c367ff actually got the license wrong, it's MIT 2021-10-23 08:25:02 -04:00
Dale Weiler e6fb4ee265 typo 2021-10-23 08:13:03 -04:00
Dale Weiler 7c336a6a82 update vendor README.md 2021-10-23 08:12:46 -04:00
Dale Weiler 71ae424aa8 add LICENSE 2021-10-23 07:56:37 -04:00
Dale Weiler 88d6407092 oops, semicolon 2021-10-23 07:51:47 -04:00
Dale Weiler e15f245339 vendor ENet 2021-10-23 07:40:40 -04:00
Jeroen van Rijn eebf49ba72 Merge pull request #1238 from awwdev/master
rename sdl2 KeyCode to Keycode
2021-10-23 03:58:32 -07:00
awwdev faa9df8735 changed KeyCode to Keycode 2021-10-23 12:46:09 +02:00
Jeroen van Rijn 8113182d5c Merge pull request #1237 from awwdev/master
memleak fix on destroy_multi_logger()
2021-10-23 03:38:54 -07:00
André 3323c2730f memleak fix on destroy_multi_logger()
data.loggers were never deleted
2021-10-23 12:24:53 +02:00
skytrias 6399f2b014 fix strip-semicolon using original file handle size 2021-10-23 00:12:32 +02:00
Mikkel Hjortshøj 7218a68e89 Update nightly.yml
Downgrading python version in nightly to use same version as local
2021-10-22 22:42:20 +02:00
Mikkel Hjortshøj 7375074d2d Update nightly.yml 2021-10-22 22:34:42 +02:00
gingerBill c9effb9b9f Correct ternary if expression type determination 2021-10-22 14:37:27 +01:00
gingerBill ef73a284e3 Fix check_remove_expr_info 2021-10-22 14:12:48 +01:00
gingerBill 28af376d10 Quick fix 2021-10-22 13:17:49 +01:00
gingerBill 48de1a01a9 Correct update propagation of type for ternary if expressions 2021-10-22 13:14:19 +01:00
gingerBill 209684d5a4 Merge branch 'master' into new-matrix-type 2021-10-21 11:48:00 +01:00
gingerBill 1405420935 Support TenraryIfAddr in lb_build_addr 2021-10-21 11:46:32 +01:00
gingerBill 48d277a3c4 Allow conversions between matrices of the same element count 2021-10-21 01:34:39 +01:00
gingerBill e0b9475378 Allow casting between square matrices of the same element type 2021-10-21 01:14:44 +01:00
gingerBill c561de33ee Add intrinsics for the matrix type 2021-10-21 00:07:10 +01:00
gingerBill d67d7168e2 Allow scalars with matrices 2021-10-21 00:04:22 +01:00
gingerBill 3b3e7550f6 Correct core_builtin_matrix.odin 2021-10-21 00:04:08 +01:00
gingerBill 9b7a25d4a9 Remove padding in stride of matrix types 2021-10-20 17:03:54 +01:00
gingerBill bb0855b35a Add builtin procedures for matrix values: determinant, adjugate, inverse, inverse_transpose, hermitian_adjoint 2021-10-20 17:00:59 +01:00
gingerBill e6f725dc2c Minor fix for parapoly matrix types 2021-10-20 17:00:14 +01:00
gingerBill 3e4c2e4932 Support conj on array and matrix types 2021-10-20 16:03:16 +01:00
jockus 2f4f6894bd Convert all vendor:OpenGL functions taking GLboolean to bool, assert on bool type size matching sizeof(unsigned char) as per the C headers 2021-10-20 15:40:55 +01:00
gingerBill 30c141ceb9 Minor clean up for lb_matrix_trimmed_vector_mask 2021-10-20 15:36:24 +01:00
gingerBill d3abc1a2b4 Add matrix_flatten - matrix[R, C]T -> [R*C]T 2021-10-20 15:33:23 +01:00
gingerBill 465c87bd5a Make transpose use SIMD if possible 2021-10-20 15:22:02 +01:00
gingerBill cdf881a378 Fix json.marshal for Matrix 2021-10-20 15:02:55 +01:00
gingerBill e8c602b98f Correct vulkan headers 2021-10-20 15:02:38 +01:00
gingerBill d0d9a3a4f4 Make lb_emit_matrix_mul SIMD if possible 2021-10-20 14:49:20 +01:00
gingerBill 9e43072113 Make lb_emit_vector_mul_matrix use SIMD if possible 2021-10-20 13:11:33 +01:00
gingerBill 1bfbed0e02 Add llvm_vector_reduce_add 2021-10-20 12:48:48 +01:00
gingerBill 0fd525d778 Make lb_emit_matrix_mul_vector use SIMD if possible 2021-10-20 12:39:38 +01:00
gingerBill 07bf64ae52 Transform matrix to mat identifier for Vulkan 2021-10-20 11:42:06 +01:00
gingerBill cee45c1b15 Add hadamard_product 2021-10-20 02:18:30 +01:00
gingerBill 68afbb37f4 Add builtin outer_product 2021-10-20 02:06:56 +01:00
gingerBill 7faca7066c Add builtin transpose 2021-10-20 01:51:16 +01:00
gingerBill 3eaac057da Unify polymorphic_assign_index logic 2021-10-20 01:26:55 +01:00
gingerBill 3f1930b76e Clean up stride logic 2021-10-20 01:26:33 +01:00
gingerBill afac1a2cc1 Unify matrix stride calculation 2021-10-20 01:17:10 +01:00
gingerBill 445696d660 Support parapoly matrices 2021-10-20 01:06:58 +01:00
gingerBill f454ac3150 Fix %#v for matrices 2021-10-20 00:43:07 +01:00
gingerBill 82b6772ea4 Support matrix literals 2021-10-20 00:40:03 +01:00
gingerBill 662cbaf425 Support indexing matrices 2021-10-19 12:13:19 +01:00
gingerBill 1556fad65a Change syntax for matrices to matrix[R, C]T 2021-10-19 11:31:11 +01:00
gingerBill 243e2e2b8a Basic support for matrix*vector, vector*matrix operations 2021-10-19 11:24:26 +01:00
gingerBill 35111b39b8 Try to support the matrix multiplication LLVM intrinsics 2021-10-18 18:57:21 +01:00
gingerBill ba331024af Very basic matrix support in backend 2021-10-18 18:16:52 +01:00
gingerBill 4c655865e5 Begin work on matrix type 2021-10-18 16:52:19 +01:00
gingerBill 7aac8df2f2 Add runtime._cleanup_runtime internal call 2021-10-18 12:28:46 +01:00
gingerBill e98e62ec13 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-16 23:39:23 +01:00
gingerBill eb3c1506f0 Remove explicit link name from runtime.memset 2021-10-16 23:39:14 +01:00
gingerBill 5bd4536372 Merge pull request #1220 from zhibog/master
Add crypto library. Additional information is included in the README.md
2021-10-16 22:42:42 +01:00
zhibog 7fa05238b8 Added note due address thread safety 2021-10-16 19:37:23 +02:00
zhibog dd7449b8b5 Fixed some typos in proc names 2021-10-16 19:20:43 +02:00
zhibog b7a0627d09 Remove the read_entire_file from the crypto utils and now use the one within core:os 2021-10-16 18:46:18 +02:00
zhibog c632125d82 Added a read_entire_file proc that only takes a handle and turned it into a proc group with the one, that takes a path 2021-10-16 18:45:25 +02:00
Jeroen van Rijn a509e112ea Merge pull request #1224 from helloguysmaster/patch-1
add GetModuleHandleA
2021-10-16 07:53:00 -07:00
Jonas Welle 7c26b0abdb add GetModuleHandleA 2021-10-16 10:43:33 -04:00
zhibog f48ee00c2f Improved API. hash_file procs now just take a file handle instead of a path 2021-10-15 20:29:25 +02:00
zhibog ced0ea515c Added note for the botan.dll to README.md 2021-10-14 23:08:21 +02:00
zhibog 8876328e4d Move botan.dll to correct directory 2021-10-14 23:03:55 +02:00
zhibog f4ff11a7ff Added botan.dll for tests 2021-10-14 22:58:20 +02:00
zhibog 77be7144c3 Add crypto library. Additional information is included in the README.md 2021-10-14 22:20:55 +02:00
gingerBill 3337d38651 Add comments to procedure groups 2021-10-13 23:39:17 +01:00
gingerBill fc3b0dcc80 Update sync_util.odin 2021-10-13 23:36:42 +01:00
gingerBill fc33cf6846 Set VertexAttribPointer related calls to use uintptr instead of rawptr for the byte offset parameter 2021-10-13 16:15:01 +01:00
gingerBill 2c469a39c7 Simplify TIME_SECTION code 2021-10-12 15:09:57 +01:00
gingerBill d0001dc11d Increase system_exec_command_line_app buffer from 4 KiB to 64 MiB, and unify some logic 2021-10-12 13:56:36 +01:00
gingerBill 68719779d7 Fix typo 2021-10-12 11:08:57 +01:00
gingerBill 2ad6aa7886 Copying file contents rather than memory mapping 2021-10-12 11:06:39 +01:00
gingerBill 75e3df6da2 Add utility procedure groups for sync primitives 2021-10-12 11:03:52 +01:00
gingerBill 753acc6971 Add wait_group_wait_with_timeout; Allow Sema to be implemented as a Wait_Group 2021-10-11 20:14:26 +01:00
gingerBill 0d258e8b55 Make many package time procedures use "contextless" calling convention 2021-10-11 20:08:38 +01:00
gingerBill 3a60bee804 Move assert to implementation file 2021-10-11 20:07:39 +01:00
gingerBill b67e0002c1 Add testing.expect_value; Improve testing.set_fail_timeout 2021-10-11 20:05:13 +01:00
gingerBill 0070119392 Add thread.create_and_start_with_* procedures 2021-10-11 19:56:29 +01:00
gingerBill 310fd1936b Clean up _futex_wait_with_timeout on Linux 2021-10-11 19:49:56 +01:00
gingerBill 077bf28d26 Separate Sema implementation from "header"; Allow for either Futex or Mutex+Cond implementations of Sema 2021-10-11 19:48:27 +01:00
gingerBill d97c6a7657 Rename futex_wake and futex_wake_all to futex_signal and futex_broadcast 2021-10-11 16:40:23 +01:00
gingerBill 46b33854c9 Add sema_wait_with_timeout 2021-10-11 16:35:04 +01:00
gingerBill 5ee3686569 Fix typo 2021-10-11 16:34:50 +01:00
gingerBill d23144fd27 Keep -vet happy 2021-10-11 15:30:23 +01:00
gingerBill e64eb631df Add testing.set_fail_timeout 2021-10-11 15:28:25 +01:00
gingerBill 129a62d4f1 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-11 15:23:44 +01:00
gingerBill 8c9299c139 Use WaitOnAddress instead of RtlWaitOnAddress 2021-10-11 15:23:39 +01:00
gingerBill 3e9b7120be Merge pull request #1216 from Tetralux/fix-io-read
Fix typo in io.read_at_least()
2021-10-11 13:57:30 +01:00
Tetralux 675ba44e67 Fix typo in io.read_at_least() 2021-10-11 12:33:27 +00:00
gingerBill 240b6aab13 Change futex_wait_with_timeout to return a boolean rather than an enum 2021-10-11 13:23:11 +01:00
gingerBill a1e8769cff Add atomic_cond_wait_with_timeout 2021-10-11 13:02:17 +01:00
gingerBill 73cba2cf13 Add cond_wait_with_timeout 2021-10-11 12:55:25 +01:00
gingerBill 49c761dc6d Fix typo 2021-10-09 19:11:26 +01:00
gingerBill 2a8d4c5bf5 Disallow or_return within defer 2021-10-09 19:11:10 +01:00
gingerBill 2b8807eb73 Keep -vet happy 2021-10-09 16:35:26 +01:00
gingerBill 2ef0e6b8f6 Update core:sync/sync2 to have a generic Futex interface, and implement the calls appropriately for each platform 2021-10-09 16:33:28 +01:00
gingerBill d386563344 Correct issue with the generated map type internals; Simplify map rehash logic to utilize resize 2021-10-07 21:23:37 +01:00
gingerBill 9ecc2ab15b Add more runtime.print_int procedures 2021-10-07 21:22:49 +01:00
gingerBill cb9101e0a0 Simplify lb_gen_map_header 2021-10-07 14:12:47 +01:00
gingerBill fd9adaf1de Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-07 13:41:26 +01:00
gingerBill af7008aa44 Allow for array programming value constants 2021-10-07 13:41:14 +01:00
Jeroen van Rijn d3a18fbe9a Merge pull request #1210 from Kelimion/png_improvements
Lots of PNG improvements
2021-10-06 14:03:47 -07:00
Jeroen van Rijn b4b53aeb71 png: Channel helper metadata. 2021-10-06 22:47:40 +02:00
Jeroen van Rijn c4b4a841d6 png: Move metadata. 2021-10-06 22:43:33 +02:00
Jeroen van Rijn 263d63aa56 png: Add more OOM checks. 2021-10-06 22:09:32 +02:00
Jeroen van Rijn 8fcd1794a6 png: Add sane compile-time maximums for dimensions + chunk sizes. 2021-10-06 21:48:22 +02:00
Jeroen van Rijn 9b5ae95677 png + compress: Rearrange error unions. 2021-10-06 20:45:29 +02:00
Jeroen van Rijn 21c6d691d8 Add additional error checking to helpers. 2021-10-06 20:10:37 +02:00
Jeroen van Rijn 2e9eec156c Revert "Merge pull request #1209 from Kelimion/append_error"
This reverts commit c9468adcfd, reversing
changes made to 879a4d49ae.
2021-10-06 19:09:28 +02:00
Jeroen van Rijn c9468adcfd Merge pull request #1209 from Kelimion/append_error
Make `append` builtins return an `Allocator_Error`.
2021-10-06 07:40:16 -07:00
Jeroen van Rijn b345176bde Make append builtins return an Allocator_Error. 2021-10-06 16:33:52 +02:00
Jeroen van Rijn 879a4d49ae Merge pull request #1208 from englerj/win32-bindings
Additional win32 bindings.
2021-10-06 04:27:09 -07:00
Josh Engler 15594706c9 Additional win32 bindings. 2021-10-05 19:09:20 -04:00
gingerBill 58e3f779f2 Remove nonsense from static_arena_init 2021-10-05 17:12:24 +01:00
gingerBill 455d64fbd4 Add error value to commit 2021-10-05 17:11:12 +01:00
gingerBill 16ca677c1f Correct mmap usage 2021-10-05 17:05:33 +01:00
gingerBill 1f1434b384 Add arena_util.odin 2021-10-05 16:42:42 +01:00
gingerBill f83370235f Add static_arena_bootstrap_new 2021-10-05 16:39:14 +01:00
gingerBill 4961aff51b Minor cleanup 2021-10-05 16:37:15 +01:00
gingerBill 0ed3143006 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-05 16:28:25 +01:00
gingerBill bc2b8b597c Add virtual.Static_Arena 2021-10-05 16:28:14 +01:00
gingerBill ccc4c641c4 Clean up Memory_Block logic 2021-10-05 16:25:30 +01:00
Jeroen van Rijn 0ca8a4ad3b Merge pull request #1207 from Kelimion/fix_1206
Remove assert from `mem.ptr_to_bytes`. Fixes #1206
2021-10-05 05:20:24 -07:00
Jeroen van Rijn 1931e3147d Remove assert from mem.ptr_to_bytes. Fixes #1206 2021-10-05 14:18:48 +02:00
gingerBill 9d9ec192f1 Rename to growing_arena.odin 2021-10-04 17:57:59 +01:00
gingerBill 586a000152 Add Protect_Flags for virtual.protect 2021-10-04 17:42:15 +01:00
gingerBill 728f143e33 Add virtual_linux.odin 2021-10-04 17:30:06 +01:00
gingerBill f2e78dcc0b Separate out the virtual memory allocation procedures
`reserve`, `commit`, `reserve_and_commit`, `decommit`, `release`, `protect`
2021-10-04 16:43:52 +01:00
gingerBill a463609e4c If an entity is inserted into a scope already exists by the same name, it will not report as an error any more 2021-10-04 12:41:33 +01:00
gingerBill e05a305764 Minor clean up 2021-10-03 12:43:11 +01:00
gingerBill a437c95fed Remove mutex from Growing_Arena; Add Growing_Arena_Temp 2021-10-03 12:41:24 +01:00
gingerBill 8fe70978ff Add @(init) usage to core:mem/virtual 2021-10-03 12:40:51 +01:00
gingerBill 647fee31f8 Correct offset_of_by_string 2021-10-03 12:34:01 +01:00
gingerBill 8af6b6fa18 Remove debug code 2021-10-03 12:32:51 +01:00
gingerBill f48f06e7b7 Add offset_of_by_string 2021-10-03 12:32:04 +01:00
gingerBill 51b5a973e2 Allow constant string value for the field argument of offset_of 2021-10-03 12:24:54 +01:00
gingerBill 2bdae52fed Add @(init) attribute for procedures, allowing for procedures to be called at startup
These procedures will be called after global variables have been initialized as normal
2021-10-03 11:53:32 +01:00
gingerBill b3a66b3950 Change c.int to PixelFormat where appropriate 2021-10-02 23:58:40 +01:00
gingerBill a971fb6e94 Make TextFormat use static internal buffers; Add TextFormatAlloc 2021-10-02 22:43:55 +01:00
gingerBill 036fa5cb24 Correct ABI for windows with LLVM 2021-10-02 18:12:34 +01:00
gingerBill 81fe50d623 Add sizes to assert message 2021-10-02 17:48:09 +01:00
gingerBill b9b9bd8612 Add message to assert; add sanity check for possible future behaviour 2021-10-02 17:44:24 +01:00
gingerBill 171a5d6476 Clean up struct_fields_index_by_increasing_offset 2021-10-02 17:43:48 +01:00
gingerBill 00671a59a0 Minor code cleanup for backend; add struct_fields_index_by_increasing_offset for future use 2021-10-02 17:22:56 +01:00
gingerBill ebca0398a7 Remove need for alignment lb_struct_has_padding_prefix 2021-10-02 16:06:42 +01:00
gingerBill 58a405cc9f Fix typos; Add MemAllocator which wraps the raylib allocation procedures into an Odin Allocator; Reimplement TextFormat using fmt.*printf 2021-10-02 15:46:55 +01:00
gingerBill 444fedd8d4 Heavily improve the LLVM struct type generation to improve ABI 2021-10-02 15:45:46 +01:00
gingerBill f7137bf367 Improvements to vendor:microui 2021-10-02 14:06:34 +01:00
gingerBill 92a0ce991e Update examples/all 2021-10-02 14:06:11 +01:00
gingerBill 1e7c60e171 Minor style change 2021-10-02 14:05:26 +01:00
gingerBill 2d2e3ed6a1 Remove dead code 2021-10-02 14:04:52 +01:00
gingerBill 21a06df5e1 Add alias for MJSON as Bitsquid 2021-10-02 14:04:41 +01:00
gingerBill c04efe8762 Merge pull request #1204 from Airbus5717/master
fix Specification link in readme
2021-10-02 11:28:15 +01:00
Airbus5717 41071ee351 fix Specification link in readme 2021-10-02 13:26:33 +03:00
gingerBill 594049027b Merge branch 'master' of https://github.com/odin-lang/Odin 2021-10-02 01:13:35 +01:00
gingerBill b1ea291942 Fix typos 2021-10-02 01:13:28 +01:00
Jeroen van Rijn 254c504465 Merge pull request #1199 from Skytrias/master
small package fixes
2021-10-01 12:15:33 -07:00
gingerBill d32d1b7e07 Add reflect.set_union_value 2021-09-30 12:04:27 +01:00
gingerBill cf94fd7b82 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-30 11:46:02 +01:00
gingerBill 6ca793f0e9 Remove deprecation from the build specific procedures 2021-09-30 11:45:56 +01:00
skytrias 9ceb6b79fd small package fixes 2021-09-29 21:47:36 +02:00
gingerBill bd1e1c66f3 Merge pull request #1188 from krux02/minor-fix-3
fix #1187
2021-09-29 19:22:56 +01:00
gingerBill 08ac2fd1b6 Rename virtual.Arena to virtual.Growing_Arena 2021-09-29 16:50:36 +01:00
gingerBill b2a36f204e Add a mutex to arena_free_all 2021-09-29 16:46:14 +01:00
gingerBill efdd5cf499 Add a mutex to virtual.Arena 2021-09-29 16:43:58 +01:00
gingerBill 805e48ae1e Add core:mem/virtual 2021-09-29 16:39:20 +01:00
gingerBill c6ff88e85a Add io.write_f16 io.write_f32 io.write_f64 2021-09-29 16:39:02 +01:00
gingerBill f99bea12c7 Allow uintptr <-> [^]T 2021-09-29 16:36:05 +01:00
gingerBill 19ac822e4a Improve reflect.Type_Info_Complex support 2021-09-29 15:08:45 +01:00
gingerBill 9d797ea225 Add more support for complex types 2021-09-29 15:02:51 +01:00
gingerBill aac290e366 Clean up json.marshal_to_writer 2021-09-29 14:50:53 +01:00
gingerBill 1d6e398f20 Add io.Error to fmt.fprintf_typeid 2021-09-29 14:49:58 +01:00
gingerBill 9fae575531 Keep -vet happy 2021-09-29 14:49:25 +01:00
gingerBill e928793e79 Correct _builder_stream_vtable 2021-09-29 14:49:06 +01:00
gingerBill e99061500d Minor clean up of n_read/n_written handling 2021-09-29 14:28:09 +01:00
gingerBill 8e2a0be804 Add an extra optional ^int parameter to most io read/write calls allowing for simplified or_return use with incrementing byte usage 2021-09-29 13:59:47 +01:00
gingerBill 94a27224b2 Deprecate strings.write_quoted_* in favour of io.write_quoted_*; make reflect.write_type a little more robust with io.Error handling 2021-09-29 13:42:58 +01:00
gingerBill 4acb4c4ee2 Split examples/all into different files 2021-09-29 13:41:29 +01:00
gingerBill b2164b5da6 Make the io/conv.odin utilities be #optional_ok 2021-09-29 13:24:42 +01:00
gingerBill 057310472e Add io.write_i128 and io.writer_u128 2021-09-29 13:21:49 +01:00
gingerBill c22f2866c7 Remove fmt dependency 2021-09-29 13:18:06 +01:00
gingerBill 07ba3e6304 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-29 13:06:13 +01:00
gingerBill 9bc12e3f38 Improve json.marshal error handling for io.Writer; Add docs for the different JSON specifications 2021-09-29 13:06:03 +01:00
gingerBill b3f2263442 Add io.write_quoted_* utility procedures to package io 2021-09-29 13:04:59 +01:00
Jeroen van Rijn 6884841ece Merge pull request #1197 from Kelimion/help
Fix -collection help typo.
2021-09-28 11:04:44 -07:00
Jeroen van Rijn 6f04c61bdf Fix -collection help typo. 2021-09-28 19:59:44 +02:00
gingerBill d452758afc Improve MJSON handling 2021-09-28 15:01:11 +01:00
gingerBill c933054872 Support json.Specification.MJSON
https://bitsquid.blogspot.com/2009/10/simplified-json-notation.html
2021-09-28 14:53:16 +01:00
gingerBill 6f872e04c8 Move redundant auto_cast error from -vet to -vet-extra 2021-09-28 12:24:51 +01:00
gingerBill ea0bf05727 Make it clear that integers are parsed separately from floats 2021-09-28 12:18:11 +01:00
gingerBill bcb07b6b9e Correct runtime.floattidf and other related i128<->f64 internal procedures 2021-09-28 12:17:36 +01:00
gingerBill edbf2bf56f Correct append_soa for #soa[dynamic][N]T 2021-09-26 13:42:53 +01:00
gingerBill 93f97defb9 Remove @private from some procedures 2021-09-26 00:08:42 +01:00
gingerBill 22827da4a2 Minor changes to microui.odin 2021-09-25 23:59:28 +01:00
gingerBill aa382959a7 Make empty arrays work on a single line with %#v 2021-09-25 21:12:10 +01:00
gingerBill 6fab93c4b3 Fix [^]u8 to cstring conversion 2021-09-25 21:11:54 +01:00
gingerBill 5e30b3eeef Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-25 18:05:42 +01:00
gingerBill 14a3ddb9af Allow for union{T} like types in json.unmarshal 2021-09-25 18:05:35 +01:00
Jeroen van Rijn f7bf55af4a Merge pull request #1194 from Kelimion/define
Allow `-define:name=string`.
2021-09-25 09:56:51 -07:00
gingerBill 6a271355a6 Add json.unmarshal 2021-09-25 17:47:45 +01:00
gingerBill 931fdd2dca Add reflect.any_base reflect.any_core 2021-09-25 17:47:23 +01:00
gingerBill e6d8fbf194 Add runtime.__get_map_header_runtime 2021-09-25 17:30:18 +01:00
gingerBill 6fa3c992b5 mem.Raw_* alias runtime.Raw_* 2021-09-25 17:29:51 +01:00
Jeroen van Rijn 2c055b0972 Allow -define:name=string.
Slightly rewrote `build_param_to_exact_value` parsing logic.

First, try to parse as a bool, then as an integer or float.
If both fail, treat the value as a string.

To force a string define for e.g. `true`, use `-define:name='true'`.
2021-09-25 18:11:30 +02:00
gingerBill 868c923770 Make map internals more robust when using mem.nil_allocator() 2021-09-25 15:55:27 +01:00
gingerBill fa0d58f96e Correct f64 -> u128/i128 generation 2021-09-25 15:38:56 +01:00
gingerBill ebc09d5e4e Add i128 and u128 parsers to strconv 2021-09-25 14:30:50 +01:00
gingerBill bfc92d0aaf Make runtime.memset use int for the length from uint 2021-09-23 23:43:29 +01:00
gingerBill 8c4197af38 Add #load_or(path_string, default_byte_slice) 2021-09-23 23:32:46 +01:00
gingerBill 374f98356c Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-23 23:25:26 +01:00
gingerBill 20529c6512 Minor simplification to #assert and #panic parsing 2021-09-23 23:25:13 +01:00
gingerBill ea555c0ccd Simplify directive parsing for expressions 2021-09-23 23:22:16 +01:00
gingerBill 0d20190b0f Merge pull request #1193 from thePHTest/master
Correct levenshtein distance
2021-09-23 17:55:16 +01:00
Phil H 3ac13d2028 Correct levenshtein distance 2021-09-23 09:22:28 -07:00
Jeroen van Rijn 868d9ba534 Merge pull request #1191 from Kelimion/vulkan-fix
vendor:vulkan: Remove unused core:c import.
2021-09-23 05:29:53 -07:00
Jeroen van Rijn c0437330e9 vendor:vulkan: Remove unused core:c import. 2021-09-23 14:21:12 +02:00
gingerBill 6a86b3c82b Cleanup hash implementation 2021-09-23 12:41:48 +01:00
gingerBill a7f59ab388 Add asserts to begin_window and begin_panel 2021-09-23 12:40:40 +01:00
gingerBill 5586c6b9c5 Update microui/README.md 2021-09-23 12:20:44 +01:00
gingerBill 964a09ef7a Add vendor:microui
This is a direct port in Odin, not bindings; utilizing Odin's rich type system
2021-09-23 12:20:01 +01:00
gingerBill 360f75a65c Keep -vet happy 2021-09-23 12:19:08 +01:00
Jeroen van Rijn 0201fa3fbb Merge pull request #1189 from strager/patch-1
Fix indentation typo
2021-09-22 01:46:38 -07:00
strager 31daf80aea Fix indentation typo 2021-09-21 23:02:15 -07:00
Arne Döring 48f496f3b3 fix #1187 2021-09-22 03:03:01 +02:00
Jeroen van Rijn 76fa037ca7 Merge pull request #1186 from Kelimion/crc64
Add CRC-64 variants: ISO 3306, ECMA 182, XZ
2021-09-21 07:36:03 -07:00
Jeroen van Rijn 6e22a6dfa5 hash: Smaller CRC-64 ISO 3306 table. 2021-09-21 16:28:35 +02:00
Jeroen van Rijn 181eabcffc hash: Add CRC-64 (ISO 3306) and inverse. 2021-09-21 16:17:01 +02:00
Jeroen van Rijn b600ffba3b Correct CRC-64 (ECMA 182) & add CRC-64 (XZ) and tests. 2021-09-21 15:17:23 +02:00
Jeroen van Rijn b3dc3f5908 Merge pull request #1182 from DanielGavin/parser-fix
Make optional semicolons the default on odin/parser, and add parser test on demo.odin
2021-09-20 12:10:19 -07:00
Daniel Gavin 0a11a6e1f6 Merge remote-tracking branch 'upstream/master' into parser-fix 2021-09-20 20:56:07 +02:00
Daniel Gavin 46d99395ce typo in filename 2021-09-20 20:53:39 +02:00
Daniel Gavin 50ee65ea9e Make default_parser use the optional_semicolons and add odin parser test. 2021-09-20 20:50:01 +02:00
Jeroen van Rijn 5840bfba62 Merge pull request #1181 from DanielGavin/parser-fix
Fix parser errors
2021-09-20 11:23:42 -07:00
Daniel Gavin a2a7647c90 Fix '>>' operand being tokenized correctly and switch statement with bare semicolon. 2021-09-20 20:12:13 +02:00
Jeroen van Rijn 70dff11b29 Merge pull request #1178 from Kelimion/new_clone
fix mem.new_clone
2021-09-19 13:19:42 -07:00
Jeroen van Rijn eb9665f836 fix mem.new_clone 2021-09-19 22:19:06 +02:00
Jeroen van Rijn bf15e63130 Revert "Merge pull request #1177 from Kelimion/new_clone"
This reverts commit efa513262e, reversing
changes made to daccfca11d.
2021-09-19 22:16:02 +02:00
Jeroen van Rijn efa513262e Merge pull request #1177 from Kelimion/new_clone
New clone
2021-09-19 13:13:44 -07:00
Jeroen van Rijn 64ce55944a fix mem.new_clone 2021-09-19 22:10:19 +02:00
gingerBill daccfca11d Merge pull request #1166 from krux02/minor-fix-2
fix compiler crash in ast_end_token
2021-09-19 12:03:11 +01:00
gingerBill ee876ad66b Strip semicolons 2021-09-19 11:59:44 +01:00
gingerBill ceebd7b23c Correct context.allocator usage 2021-09-19 11:59:31 +01:00
Jeroen van Rijn e760535dba lz4: Start of implementation. 2021-09-19 12:51:07 +02:00
Jeroen van Rijn 2b77f5b72f Merge pull request #1175 from Kelimion/defer_delete
Make sure to `delete` on the right allocator.
2021-09-19 03:19:33 -07:00
Jeroen van Rijn 72fe1e88a3 Make sure to delete on the right allocator. 2021-09-19 12:19:01 +02:00
gingerBill 505113ee2d Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-18 15:11:15 +01:00
gingerBill 71f2289c20 Fix #1174 2021-09-18 15:10:29 +01:00
gingerBill 21b6ef8757 Merge pull request #1156 from odin-lang/llvm-12.0.1-windows
Update Windows to LLVM 12.0.1
2021-09-18 13:03:29 +01:00
gingerBill b427bd8105 Correct XXH_DISABLE_PREFETCH usage 2021-09-18 12:59:54 +01:00
gingerBill 6855538729 Merge branch 'master' into llvm-12.0.1-windows 2021-09-18 12:55:13 +01:00
gingerBill 05ac2002e0 Force file copy on odin strip-semicolon 2021-09-18 12:52:43 +01:00
gingerBill 73427d3ab3 Merge pull request #1173 from odin-lang/vendor-miniaudio
`vendor:miniaudio`
2021-09-18 11:58:46 +01:00
gingerBill 3713f11461 Refactor init_tokenizer_with_data to file memory mapping (Windows only currently) 2021-09-18 11:58:27 +01:00
gingerBill 08ae186d8e Correct foreign import paths 2021-09-17 14:42:39 +01:00
gingerBill 54b7ed5b52 Update foreign imports for linux 2021-09-17 14:11:43 +01:00
gingerBill 64f5ba6ba1 Add the remaining of the miniaudio API 2021-09-17 14:09:45 +01:00
gingerBill f38b7ebf42 Begin adding vendor:miniaudio 2021-09-17 12:57:52 +01:00
gingerBill 4cb7f05644 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-16 23:03:25 +01:00
gingerBill 91d089ffe2 Minor clean up to strings.odin 2021-09-16 23:03:16 +01:00
Jeroen van Rijn d2aa6af882 Merge pull request #1171 from Kelimion/vs2022
VS: Fix compilation using VS 2022.
2021-09-16 04:28:24 -07:00
Jeroen van Rijn 0d12432d3f VS: Fix compilation using VS 2022. 2021-09-16 13:24:20 +02:00
Jeroen van Rijn 6d7df6f335 Merge pull request #1170 from Kelimion/xxhash
xxhash: Add tests for streaming input.
2021-09-15 14:33:20 -07:00
Jeroen van Rijn b6d0a8fe0c xxhash: Add tests for streaming input. 2021-09-15 23:32:48 +02:00
Jeroen van Rijn 662d27b796 Finish xxHash implementation. 2021-09-15 20:06:07 +02:00
gingerBill de00c7c9a8 Add bits.log2 2021-09-15 15:18:20 +01:00
gingerBill 736a763859 Add stb libs for Windows directly 2021-09-15 14:30:11 +01:00
gingerBill 4eda1b0598 Update appropriate parameters to the corresponding boolean types 2021-09-15 14:21:31 +01:00
gingerBill 2e21312059 Remove -march=native from stb/src/Makefile 2021-09-15 14:09:12 +01:00
gingerBill 22218fff67 Update vendor/README.md 2021-09-14 22:59:35 +01:00
gingerBill e7ea09a93b Add vendor:stb/vorbis 2021-09-14 22:35:22 +01:00
gingerBill 6f182ae5ae Add vendor:stb/easy_font -- source port of stb_easy_font.h 2021-09-14 22:12:23 +01:00
gingerBill 43ebee4e91 Revert build.bat 2021-09-14 21:44:41 +01:00
gingerBill cb2437959c Add stb_image_resize to vendor:stb/image 2021-09-14 21:44:26 +01:00
gingerBill 61efbf8684 Merge pull request #1168 from odin-lang/vendor-stb
`vendor:stb` - Add stb libraries (image+image_write, rect_pack, truetype)
2021-09-14 18:31:33 +01:00
gingerBill da14292369 Minor corrections to stb_truetype.odin 2021-09-14 18:22:04 +01:00
gingerBill b0d5dde3d7 Add build_vendor.bat 2021-09-14 18:12:14 +01:00
gingerBill 7189625cf5 Add stb libraries (image+image_write, rect_pack, truetype) 2021-09-14 17:54:50 +01:00
Jeroen van Rijn 1012055ba9 Merge pull request #1167 from Skytrias/patch-1
raylib linux - add system dependencies
2021-09-14 18:23:56 +02:00
Michael Kutowski 54e16bed0a add linux system dependencies for raylib 2021-09-14 18:17:08 +02:00
Arne Döring 9772e3a40b spaces to tabs 2021-09-14 12:14:41 +02:00
Arne Döring 442c25bf82 fix crash for ast_end_token 2021-09-14 11:44:10 +02:00
Jeroen van Rijn c2707618d9 Merge pull request #1165 from Kelimion/xxhash
Add XXH3-64 + tests.
2021-09-13 21:06:08 +02:00
Jeroen van Rijn a641ef95c0 Add XXH3-64 + tests. 2021-09-13 20:58:26 +02:00
gingerBill 4e4ac460e5 Merge pull request #1164 from odin-lang/llvm-explicit-padding
LLVM Struct Types with Explicit Padding
2021-09-13 18:23:58 +01:00
gingerBill 526a42c6ca Remove custom alignment limit 2021-09-13 16:44:01 +01:00
gingerBill 8de728e3dc LLVM Code Generator: Add explicitly padding between fields in LLVM struct types 2021-09-13 16:40:24 +01:00
Jeroen van Rijn e9b9d15de7 Merge pull request #1163 from Kelimion/bluetooth
sys: Add Windows Bluetooth APIs.
2021-09-13 14:37:02 +02:00
Jeroen van Rijn a9f4c90c79 sys: Add Windows Bluetooth APIs. 2021-09-13 14:31:52 +02:00
Jeroen van Rijn 6ca58dd64e Merge pull request #1162 from rasa-silva/fix_osx_readdir
Fix read_dir on OSX
2021-09-13 13:51:24 +02:00
Ricardo Silva 01aa0c4151 Fix read_dir on OSX 2021-09-13 12:34:36 +01:00
gingerBill be68bf9f26 Only store field_index remove field_src_index (for the time being) 2021-09-13 11:29:46 +01:00
gingerBill 15c309b0b8 Make permanent_allocator() thread local 2021-09-13 01:39:41 +01:00
gingerBill 042dbda47f Replace many uses of heap_allocator() with permanent_allocator() 2021-09-13 01:30:30 +01:00
gingerBill 2d7aea79b9 Make TypeStructl.tags a pointer from a slice (reduce memory usage) 2021-09-13 01:23:37 +01:00
gingerBill 31ed4f15a8 Remove debug code 2021-09-13 01:14:31 +01:00
gingerBill 71bffd46dc Reduce size of Type 2021-09-13 01:14:17 +01:00
gingerBill f5bc95eb34 More culling 2021-09-13 01:07:24 +01:00
gingerBill fb8fa5217d Begin minimize Type size by replacing Array with Slice etc 2021-09-13 00:58:39 +01:00
gingerBill 6585601765 Sort enums 2021-09-12 18:51:22 +01:00
gingerBill 2a1193ee54 Add heuristics to make pointers [^] where appropriate for vulkan 2021-09-12 18:50:02 +01:00
gingerBill 519308a16a Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-12 16:47:24 +01:00
gingerBill 3195fac92b Fix slice indices endianness 2021-09-12 16:47:17 +01:00
gingerBill 15921d032c Correct endianness on slicing 2021-09-12 16:45:57 +01:00
Jeroen van Rijn 813d3dc319 Merge pull request #1159 from Kelimion/xxhash
xxhash: Add custom secret tests.
2021-09-12 12:18:10 +02:00
Jeroen van Rijn ada3be05fb xxhash: typo. 2021-09-12 12:14:49 +02:00
Jeroen van Rijn 36a2cf0369 xxhash: Add custom secret tests. 2021-09-12 12:11:39 +02:00
Jeroen van Rijn 827363708c Merge pull request #1158 from Kelimion/xxhash
xxhash: Extra (generated) tests.
2021-09-11 23:48:47 +02:00
Jeroen van Rijn 00c1d34108 xxhash: Extra (generated) tests. 2021-09-11 23:45:08 +02:00
Jeroen van Rijn 87f1815486 Merge pull request #1157 from Kelimion/math_big_llvm12
LLVM 12 big math test workaround.
2021-09-11 20:43:43 +02:00
Jeroen van Rijn f978e74773 LLVM 12 big math test workaround. 2021-09-11 20:36:09 +02:00
gingerBill 9e018b642e Fix typo 2021-09-11 17:32:06 +01:00
gingerBill 7260d3cecb Add intrinsics.prefetch_* procedures 2021-09-11 17:30:44 +01:00
gingerBill c51c002ffa Update Windows to LLVM 12.0.1 2021-09-11 17:06:29 +01:00
gingerBill a5b4b73544 Add error message for minimum required LLVM 2021-09-11 16:53:39 +01:00
gingerBill e3359a2639 Prepare for LLVM 12.0.1 compatibility 2021-09-11 16:53:18 +01:00
gingerBill 344abf2cb2 Make core and vendor adhere to -vet, -strict-style, and -disallow-do 2021-09-11 16:40:19 +01:00
gingerBill 93593f4721 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-11 16:33:12 +01:00
gingerBill ab85571ae6 Minor improvements to mem.odin 2021-09-11 16:33:05 +01:00
Jeroen van Rijn 6769a00929 Merge pull request #1154 from Kelimion/xxhash
xxhash: Add XXH3_128 + test vectors.
2021-09-11 15:52:15 +02:00
Jeroen van Rijn 5f920414d7 xxhash: Disable prefetch on Linux. 2021-09-11 15:45:17 +02:00
Jeroen van Rijn 72782d9035 xxhash: Fix test on Linux. 2021-09-11 15:39:11 +02:00
Jeroen van Rijn eaefbc43cb xxhash: Add XXH3_128 + test vectors. 2021-09-11 15:28:49 +02:00
gingerBill 1f1d8ef884 Use [^] where appropriate 2021-09-10 23:53:16 +01:00
gingerBill 6899c7b7dd Using vendor:vulkan types in vendor:sdl2 where appropriate 2021-09-10 23:45:39 +01:00
gingerBill b712c84afb Fix typo 2021-09-10 16:37:43 +01:00
gingerBill 9980f81062 Add other constants to c and libc 2021-09-10 16:14:39 +01:00
gingerBill 297cdde144 Change defaults of c.int_fast16_t on other platforms 2021-09-10 16:08:39 +01:00
gingerBill 461ca40848 Add procs.odin 2021-09-10 16:01:17 +01:00
gingerBill 12af657369 Unify memset usage across platforms and core:c/libc 2021-09-10 15:59:14 +01:00
gingerBill c519ab9401 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-10 15:42:00 +01:00
gingerBill 99df0f1b12 libc changes: unify c and libc types; Add [^]T where appropriate 2021-09-10 15:41:51 +01:00
Jeroen van Rijn 6daa8c8c59 Merge pull request #1153 from rasa-silva/fix_osx_stat_calls
Use lstat64/fstat64 instead for OSX
2021-09-10 15:24:01 +02:00
Ricardo Silva 87408aedb5 replace lstat/fstat with lstat64/fstat64 since they return the correct values 2021-09-10 14:18:08 +01:00
Jeroen van Rijn 809b3a87af Merge pull request #1150 from rasa-silva/fix_osx_absolute_path_from_handle
Fix `absolute_path_from_handle` on OSX
2021-09-09 18:19:36 +02:00
Ricardo Silva 43c578d8b7 Fix absolute_path_from_handle on OSX 2021-09-09 17:12:26 +01:00
Jeroen van Rijn 31a5b2bbbd Merge pull request #1151 from Kelimion/xxhash
Fix typos
2021-09-09 16:59:23 +02:00
Jeroen van Rijn e5652da6da Fix typo. 2021-09-09 16:57:58 +02:00
Jeroen van Rijn 05e303e9a0 Make QPC thread local again. 2021-09-09 16:16:06 +02:00
Jeroen van Rijn fc66ce9dd6 Merge pull request #1149 from Kelimion/xxhash
Add `xxhash` 32-bit and 64-bit digest versions.
2021-09-09 16:12:29 +02:00
Jeroen van Rijn f04614b1f1 Make -vet happy. 2021-09-09 16:05:59 +02:00
Jeroen van Rijn 637685316d Add xxhash tests to CI. 2021-09-09 16:01:44 +02:00
Jeroen van Rijn f16e98b074 Add xxhash benchmark. 2021-09-09 15:26:57 +02:00
Jeroen van Rijn f5d5417af7 xxhash: Initial implementations. 2021-09-09 15:26:57 +02:00
gingerBill e65e0b5db2 Add -strict-style-init-only 2021-09-09 11:06:19 +01:00
gingerBill 56bd1e2d70 Simplify strings.write_byte and strings.write_bytes 2021-09-09 00:38:16 +01:00
gingerBill a70ecdba6e Merge pull request #1145 from oskarnp/fix-raylib-configflag
Fix ConfigFlag.INTERLACED_HINT for raylib.odin
2021-09-08 21:51:41 +01:00
Oskar Nordquist 187e6d3ab7 Fix ConfigFlag.INTERLACED_HINT for raylib.odin 2021-09-08 22:33:18 +02:00
gingerBill 2786c30736 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-08 21:10:34 +01:00
gingerBill 18ca975d33 Update raylib.lib 2021-09-08 21:10:29 +01:00
Jeroen van Rijn eb76b00a5e Merge pull request #1144 from Kelimion/test_runner
Custom test runner.
2021-09-08 21:21:57 +02:00
Jeroen van Rijn 66ead6cf09 Also use custom test runner on Linux. 2021-09-08 21:21:36 +02:00
Jeroen van Rijn e6905f8657 Custom test runner. 2021-09-08 21:17:16 +02:00
gingerBill 027d69678a Add vendor/raylib/rlgl.odin 2021-09-08 19:40:18 +01:00
gingerBill 0262539f68 Add vendor/raylib/easings.odin 2021-09-08 19:11:35 +01:00
gingerBill bff66ff600 Remove unnecessary operations 2021-09-08 19:07:25 +01:00
gingerBill d36329b8ec Add binaries for raylib on "linux" and "darwin" 2021-09-08 18:15:20 +01:00
gingerBill 7e859c3e75 Update vendor/README.md 2021-09-08 18:10:10 +01:00
gingerBill 5bcb47989d Allow vendor:raylib to use core:math/linalg types with -define:RAYLIB_USE_LINALG=true 2021-09-08 18:08:38 +01:00
gingerBill e5fbf45c42 Add vendor:raylib (core only) 2021-09-08 18:04:05 +01:00
gingerBill 123db3a23d Fix typo 2021-09-08 14:55:07 +01:00
gingerBill d29a0c6680 Add a minimum alignment on *nix for the compiler in heap_allocator_proc 2021-09-08 14:53:42 +01:00
gingerBill ff40e47042 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-08 14:45:59 +01:00
gingerBill 76419383a8 Add some minor sanity checks to the compiler's heap_allocator_proc on Darwin 2021-09-08 14:45:53 +01:00
Jeroen van Rijn dc14b66c98 Merge pull request #1141 from Kelimion/test_timeout
Try to address test timeouts.
2021-09-08 14:34:53 +02:00
Jeroen van Rijn e831e919a6 Try to address test timeouts. 2021-09-08 14:30:11 +02:00
gingerBill 3aa2924a06 Remove trailing ; in vulkan wrapper 2021-09-08 13:28:41 +01:00
gingerBill 36151d227a Update vulkan generator tool 2021-09-08 13:22:29 +01:00
gingerBill e0ee59084e Add calling convention "system" which is an alias for "stdcall" on Windows and "cdecl" on other platforms 2021-09-08 13:22:03 +01:00
gingerBill 8ff898079f Minor correct for freebsd 2021-09-08 13:14:23 +01:00
gingerBill 5006674a9b Correct math/big 2021-09-08 13:14:13 +01:00
gingerBill ca33cb990b Strip semicolons in core which were missing 2021-09-08 13:12:38 +01:00
gingerBill d4f5ef046d Remove goto in favour of multiple exits 2021-09-08 11:58:01 +01:00
gingerBill 30554f4758 Correct PointInRect 2021-09-08 11:49:30 +01:00
gingerBill 83bd7c73c4 Fix #1120 code generation 2021-09-08 11:49:07 +01:00
gingerBill 3754af62d6 Correct "contextless" stuff in mem 2021-09-08 11:43:00 +01:00
gingerBill 12296cec2c Fix typo 2021-09-08 11:38:22 +01:00
gingerBill a9f4273514 Make many mem procedures "contextless" 2021-09-08 11:18:05 +01:00
gingerBill 72508dbce3 Fix code gen bug for slicing multi pointers 2021-09-08 11:14:26 +01:00
gingerBill 3e459ba16b Correct SDL.OpenURL 2021-09-08 11:09:24 +01:00
Jeroen van Rijn 98d25cdf4d Merge pull request #1140 from Kelimion/compress_tests
Move `math/big` tests and integrate `strings` test into CI.
2021-09-07 20:27:36 +02:00
Jeroen van Rijn ce2f926ff7 Separate math/big test. 2021-09-07 20:24:02 +02:00
Jeroen van Rijn c0c7b4cbda Rename CI tests. 2021-09-07 20:13:03 +02:00
Jeroen van Rijn fcb23abce4 Tests: Integrate strings into CI. 2021-09-07 19:57:08 +02:00
Jeroen van Rijn f7601a759b Move math/big tests under tests/. 2021-09-07 19:51:56 +02:00
Jeroen van Rijn 49011f5198 Merge pull request #1139 from rasa-silva/index_any_fix
Fix strings.index_any on small strings
2021-09-07 19:49:14 +02:00
Ricardo Silva f6d496c81d Fix strings.index_any on small strings 2021-09-07 18:38:10 +01:00
Jeroen van Rijn 1dffd4ea3d Merge pull request #1138 from Kelimion/compress_tests
Add Makefile for tests.
2021-09-07 19:16:53 +02:00
Jeroen van Rijn 78e923b6b0 Add Makefile for tests. 2021-09-07 19:11:06 +02:00
Jeroen van Rijn 1012f20d3b Merge pull request #1136 from Kelimion/compress_tests
Beginning of CI tests for PNG, GZIP and ZLIB
2021-09-07 18:37:55 +02:00
Jeroen van Rijn 1ab6a765da Set relative path for Odin. 2021-09-07 18:30:54 +02:00
Jeroen van Rijn 6954076f15 CI tests for PNG, GZIP + ZLIB. 2021-09-07 18:25:49 +02:00
Jeroen van Rijn 56de14fd46 image: Fix download script. 2021-09-07 17:59:17 +02:00
Jeroen van Rijn 74a883de04 Add PNG test suite asset download to CI. 2021-09-07 17:53:48 +02:00
Jeroen van Rijn c0b07c71f0 png: Add test suite asset download script. 2021-09-07 17:50:47 +02:00
Jeroen van Rijn de91433cb6 Merge pull request #1135 from Kelimion/strip-semicolons
Strip ;
2021-09-07 15:49:20 +02:00
Jeroen van Rijn ed0c3eb0a8 Strip ; 2021-09-07 15:47:22 +02:00
Jeroen van Rijn 1d57a91395 Merge pull request #1134 from rasa-silva/master
printer default_style should not add semicolons
2021-09-07 15:26:45 +02:00
Ricardo Silva cce76ed614 printer default_style should not add semicolons 2021-09-07 14:18:55 +01:00
Jeroen van Rijn 5a77a10f0a Merge pull request #1133 from Kelimion/strip-semicolons
testing: Strip ; from test runner.
2021-09-07 15:07:20 +02:00
Jeroen van Rijn 97a46f664d testing: Strip ; from test runner. 2021-09-07 14:46:53 +02:00
Jeroen van Rijn aa5b1c9c97 Merge pull request #1132 from Kelimion/bigint
big: Run tests under CI.
2021-09-07 14:21:06 +02:00
Jeroen van Rijn fbebf4bc4e big: Add Python implementation of LCM. 2021-09-07 14:17:14 +02:00
Jeroen van Rijn abb15ddb38 big: Implement isqrt in Python for the tests. 2021-09-07 13:55:37 +02:00
Jeroen van Rijn 4db5683011 big: CI print Python3 version. 2021-09-07 13:31:12 +02:00
Jeroen van Rijn c4ec459d28 bit: Force Python3 for CI. 2021-09-07 13:26:34 +02:00
Jeroen van Rijn 86cfb2ea82 big CI: Set relative path to Odin. 2021-09-07 13:22:44 +02:00
Jeroen van Rijn 0605a9f239 big: Run tests under CI. 2021-09-07 13:17:47 +02:00
Jeroen van Rijn 11c298775e Merge pull request #1131 from Kelimion/bigint
big: Split tests into their own package.
2021-09-07 12:15:11 +02:00
Jeroen van Rijn b8de25c864 Merge branch 'master' into bigint 2021-09-07 12:07:03 +02:00
Jeroen van Rijn 008048e199 big: Move tests into their own package. 2021-09-07 12:06:58 +02:00
Jeroen van Rijn fd256002b3 Merge pull request #1130 from Kelimion/bigint
big: Remove `core:fmt` usage + Add a little demo to examples/demo.
2021-09-06 23:35:57 +02:00
Jeroen van Rijn 48bfce2efc demo: Fix typo. 2021-09-06 23:32:32 +02:00
Jeroen van Rijn 5619b349be big: Remove core:fmt usage + Add a little demo to examples/demo. 2021-09-06 23:26:19 +02:00
Jeroen van Rijn b0edac58b9 Merge pull request #1128 from Kelimion/semicolons
compress: Update BSD-3 license + remove semicolons from compressed ex…
2021-09-06 21:37:09 +02:00
Jeroen van Rijn 2c13315e72 compress: Update BSD-3 license + remove semicolons from compressed example. 2021-09-06 21:33:40 +02:00
gingerBill 0434281f73 Strip semicolons; Make odin strip-semicolon replace .. with ..= if used as a binary operator 2021-09-06 20:15:59 +01:00
gingerBill 3bf005bfc5 Remove redundant semicolons from comments 2021-09-06 20:05:41 +01:00
gingerBill adcb39ef29 Update tag line 2021-09-06 19:52:36 +01:00
gingerBill 3ebfaf5f4c Update README.md 2021-09-06 19:50:08 +01:00
gingerBill 97a1147537 Correct fix to heap_allocator_proc in compiler 2021-09-06 19:34:44 +01:00
gingerBill b63d49aafa Merge pull request #1112 from odin-lang/optional-semicolons
Optional Semicolons
2021-09-06 19:29:08 +01:00
Jeroen van Rijn db8f0874bd Merge pull request #1127 from Kelimion/examples
examples: Add `libc` to `examples/all`.
2021-09-06 18:45:44 +02:00
Jeroen van Rijn 3ac12a4edf examples: Add libc to examples/all. 2021-09-06 18:42:26 +02:00
gingerBill f5615b204c Minor fix to heap_allocator_proc in common_memory.cpp 2021-09-06 16:50:13 +01:00
gingerBill 2800d4b8d0 Merge branch 'master' into optional-semicolons 2021-09-06 16:46:57 +01:00
gingerBill bc15ce302c Add dummy docs for intrinsics.syscall on Linux and Darwin 2021-09-06 15:49:51 +01:00
gingerBill 31f779f1a4 intrinsics.alloca now returns [^]u8 2021-09-06 15:45:05 +01:00
gingerBill a3a891a7f4 Add intrinsics.is_package_imported(<string>) 2021-09-06 15:41:09 +01:00
Jeroen van Rijn b31a24e5e8 Merge pull request #1126 from Kelimion/bigint
Add `internal_int_(pack, unpack)`.
2021-09-06 13:02:50 +02:00
Jeroen van Rijn de5d897b5c Add internal_int_(pack, unpack). 2021-09-06 12:57:48 +02:00
Jeroen van Rijn 7db0c50e63 Merge pull request #1124 from Kelimion/bigint
big: Add ASCII file import/export.
2021-09-05 15:54:01 +02:00
Jeroen van Rijn 3faac14d62 big: Add ASCII file import/export. 2021-09-05 15:50:23 +02:00
Jeroen van Rijn b2fa4ec675 Merge pull request #1123 from Kelimion/bigint
big: Add Extended Euclidean algorithm.
2021-09-05 14:07:14 +02:00
Jeroen van Rijn f33d0725db big: Add Extended Euclidean algorithm. 2021-09-05 14:03:02 +02:00
Jeroen van Rijn b45842c33f Merge pull request #1122 from Kelimion/bigint
big: Add `internal_random_prime`.
2021-09-05 10:41:50 +02:00
Jeroen van Rijn 1f5ce91ae2 big: Add internal_random_prime. 2021-09-05 10:40:35 +02:00
Jeroen van Rijn d7627744da Merge pull request #1121 from Kelimion/bigint
big: Add `internal_int_prime_next_prime`.
2021-09-04 16:43:43 +02:00
Jeroen van Rijn f2c5c26f2c big: Add internal_int_prime_next_prime. 2021-09-04 16:31:05 +02:00
Jeroen van Rijn 6d07bd3299 Merge pull request #1119 from Kelimion/bigint
big: Add Lucas-Selfridge primality test
2021-09-04 00:04:22 +02:00
Jeroen van Rijn 52da5b8724 big: Default to Frobenius-Underwood. It's 10% faster than Lucas-Selfridge. 2021-09-03 23:54:54 +02:00
Jeroen van Rijn b1ed7fc6b9 big: Add Lucas-Selfridge. 2021-09-03 23:54:54 +02:00
gingerBill e3809f5c1b Allow comparisons of any if reflect.equal if including_indirect_array_recursion is enabled 2021-09-03 15:52:47 +01:00
gingerBill 4b7dcc1513 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-03 15:49:35 +01:00
gingerBill c9f4fdc856 Update reflect.equal to support more types 2021-09-03 15:49:29 +01:00
Jeroen van Rijn 8178a2e7ce Merge pull request #1118 from Kelimion/bigint
big: Fix internal_int_mod for inputs with opposite signs.
2021-09-03 14:52:35 +02:00
Jeroen van Rijn 70e12f7a1c big: Fix internal_int_mod for inputs with opposite signs.
This threw off Frobenius-Underwood.
2021-09-03 14:50:26 +02:00
gingerBill 11ae87cc2f Add including_indirect_array_recursion argument to reflect.equal 2021-09-03 12:00:43 +01:00
gingerBill b0f1b1ca16 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-09-03 11:02:38 +01:00
gingerBill 7ed4f01d02 Add reflect.equal and reflect.not_equal 2021-09-03 11:02:31 +01:00
Jeroen van Rijn 07f7d14d2c Merge pull request #1117 from Kelimion/bigint
big: Add Frobenius-Underwood, Miller-Rabin and primality testing.
2021-09-03 01:39:58 +02:00
Jeroen van Rijn eecc786bd2 big: Add Frobenius-Underwood. 2021-09-03 01:25:18 +02:00
Jeroen van Rijn 7fa04fa018 big: Fix M-R. 2021-09-02 19:59:59 +02:00
Jeroen van Rijn 31918d3b8f big: Add internal_int_is_prime. 2021-09-02 18:31:08 +02:00
Jeroen van Rijn e639c61499 big: Add Miller-Rabin. 2021-09-01 22:06:07 +02:00
Jeroen van Rijn e2f035d6ee Merge pull request #1113 from Kelimion/bigint
big: Add `expt_mod`, new comparison helpers, etc.
2021-09-01 19:25:52 +02:00
Jeroen van Rijn ae354731ed big: Add ; after proc map. 2021-09-01 19:18:13 +02:00
Jeroen van Rijn 671b413b15 big: Use new comparison helpers. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn 335d361fc6 big: Add comparison helpers. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn df29d10210 big: Add internal_int_kronecker. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn fd83cbf40b big: Add ilog2. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn 7d7ed6b95f big: Add internal_int_exponent_mod. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn a056e19434 big: Cue up internal_int_exponent_mod wrapper function. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn 7d0dedf951 big: Add Diminished Radix reduction. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn ee04fb1ce1 big: Remove temporary prints. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn 2110778040 big: Add internal_int_exponent_mod_fast. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn 65a15e9c06 big: Add internal_int_exponent_mod. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn c3a70ac277 Big: Added Barrett reduction setup. 2021-09-01 19:13:47 +02:00
Jeroen van Rijn 5e520f4e08 big: Add reduce_2k. 2021-09-01 19:13:47 +02:00
gingerBill b2cf0755f2 Add vendor to nightly.yml 2021-09-01 13:08:26 +01:00
gingerBill 720884e0f1 Strip even more semicolons if followed by a } or ) on the same line 2021-08-31 23:47:57 +01:00
gingerBill 773a766b83 Strip semicolon if followed by a } or ) on the same line 2021-08-31 23:47:20 +01:00
gingerBill 169e717021 Remove debug message 2021-08-31 22:49:18 +01:00
gingerBill 72a741554c Remove unneeded semicolons from demo 2021-08-31 22:45:26 +01:00
gingerBill cd09068e33 Correct parsing rules for #assert directives for semicolons 2021-08-31 22:45:08 +01:00
gingerBill cd4687cb13 Delete unneeded demo 2021-08-31 22:34:22 +01:00
gingerBill b810781368 Remove unneeded semicolon from examples/demo and examples/all 2021-08-31 22:33:53 +01:00
gingerBill 82f58aa3de Remove unneeded semicolons from vendor 2021-08-31 22:33:19 +01:00
gingerBill f57201bbd1 Remove unneeded semicolons from the core library 2021-08-31 22:32:53 +01:00
gingerBill 2db6fea665 Remove dead code and add debug messages 2021-08-31 22:31:43 +01:00
gingerBill b450a853d5 Strip unneeded semicolons from vendor library 2021-08-31 22:26:58 +01:00
gingerBill 251da264ed Remove unneeded semicolons from the core library 2021-08-31 22:21:13 +01:00
gingerBill b176af2742 Add semicolon stripping command: odin strip-semicolon, has the same parameters as odin check 2021-08-31 22:20:36 +01:00
gingerBill 1fff96e088 Make -insert-semicolon the default now 2021-08-31 21:13:53 +01:00
gingerBill d399d2256b Change to [^][N] to just [^] 2021-08-31 20:39:32 +01:00
Jeroen van Rijn 27fd702692 Merge pull request #1111 from Kelimion/libtommath
Slim down LibTomMath compile.
2021-08-29 16:01:42 +02:00
gingerBill 5f29288254 Remove Syscall type 2021-08-29 15:00:35 +01:00
gingerBill 7c108dbf48 Update usage of syscall to use the intrinsics 2021-08-29 14:56:47 +01:00
Jeroen van Rijn 5c7cb393dc Slim down LibTomMath compile. 2021-08-29 15:54:56 +02:00
gingerBill 54b37573c9 Add intrinsics.syscall (for Linux and Darwin only) 2021-08-29 13:17:06 +01:00
gingerBill c3a64c2a59 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-29 11:45:16 +01:00
gingerBill a5c31bbee0 Add map_insert which returns the pointer to inserted value 2021-08-29 11:45:11 +01:00
Jeroen van Rijn d6bd56da2c Merge pull request #1109 from Kelimion/makefile
Fix `Makefile`.
2021-08-28 22:41:06 +02:00
Jeroen van Rijn 17d31bfad6 Fix Makefile. 2021-08-28 22:40:38 +02:00
Jeroen van Rijn 89ffd40d70 Merge pull request #1108 from Kelimion/bigint
big: Add two more asymptotically optimal multiplication methods.
2021-08-28 18:19:55 +02:00
Jeroen van Rijn 737b4fde1c big: Add _private_int_mul_balance. 2021-08-28 18:17:57 +02:00
Jeroen van Rijn 2cfd6b7024 big: Add _private_int_mul_high. 2021-08-28 14:59:13 +02:00
gingerBill 713cd728ba Merge pull request #1107 from odin-lang/mv/libc-errors
Fix libc errors in Windows and add some tests.
2021-08-28 12:51:22 +01:00
vassvik f9bea5b791 Updated comment for Windows version of setjmp. 2021-08-28 13:41:14 +02:00
Jeroen van Rijn 586641d77f Merge pull request #1106 from Kelimion/bigint
big: Add `int_is_square` and Montgomery Reduction.
2021-08-28 13:36:36 +02:00
vassvik 8ca4286624 Add core:c/libc tests 2021-08-28 13:32:32 +02:00
vassvik 165118c641 Fix runtime crash for setjmp in Windows related to an hidden second argument not normally accessible needing to be set to 0. 2021-08-28 13:32:13 +02:00
Jeroen van Rijn 852643e6ba Add tests for `internal_int_is_square'. 2021-08-28 13:27:46 +02:00
vassvik 102d080a31 Fix core:c/libc Windows compilation errors by linking to the right libraries.
Fix some name typos and missing types in Windows.
Add explicit cast on MB_CUR_MAX
2021-08-28 13:27:41 +02:00
Jeroen van Rijn ec4cae4f04 big: Add int_is_square. 2021-08-27 16:41:16 +02:00
Jeroen van Rijn 4153898c55 big: Add Montgomery Reduction. 2021-08-27 16:41:16 +02:00
Jeroen van Rijn 33df335ec9 big: Add internal_int_montgomery_calc_normalization. 2021-08-27 16:41:16 +02:00
Jeroen van Rijn 893cc013b5 big: Add Montgomery reduction. 2021-08-27 16:41:16 +02:00
gingerBill b88e945268 ERROR_BLOCK() any usages of "Did you mean?" like behaviour whilst iterating across a scope entry map 2021-08-27 12:14:51 +01:00
gingerBill bf56e3ea8d Improve strings.index_any and strings.last_index_any 2021-08-27 12:07:57 +01:00
gingerBill 284acc37f9 Update SDL scancodes to have the same C enums equivalent global values 2021-08-27 11:38:29 +01:00
gingerBill 582559f7ac Correct did you mean logic and make thread-safe-er 2021-08-27 11:18:38 +01:00
gingerBill 53556d9bd2 Disable local mutex for the time being. 2021-08-26 23:16:57 +01:00
gingerBill da79124e5d Use local mutex for each AstFile.arena 2021-08-26 23:10:15 +01:00
gingerBill 2f34f1283a Make thread_join be more correct 2021-08-26 22:42:56 +01:00
gingerBill f973d271cf Add mutex around condition_broadcast 2021-08-26 22:28:09 +01:00
gingerBill 4625b25287 Wrap linux specific code for internal_thread_proc 2021-08-26 22:26:51 +01:00
gingerBill 8d8b3fd071 Add missing header 2021-08-26 22:24:26 +01:00
gingerBill a852c17614 Don't permit any signal delivery to threads on Linux 2021-08-26 22:20:10 +01:00
gingerBill b33bf3f704 Correct race condition and incorrect usage of condition_signal outside of a mutex lock 2021-08-26 22:17:51 +01:00
gingerBill 726788a483 Treat Type_Tuple closer to a Type_Struct in lb_type 2021-08-26 22:01:02 +01:00
gingerBill cdd3560702 Merge pull request #1103 from odin-lang/new-thread-pool
Improved Thread Pool implementation for the Compiler
2021-08-26 21:44:02 +01:00
gingerBill 6d49df1d87 Don't use the thread pool if worker count is 0 2021-08-26 21:40:54 +01:00
gingerBill ac191bd31f Simplify logic for -thread-count:1 2021-08-26 21:30:23 +01:00
gingerBill ad3a3547d6 Unify thread pool logic across the rest of the compiler, using a global thread pool 2021-08-26 21:22:30 +01:00
gingerBill aba14c43ac Fix typo 2021-08-26 17:57:29 +01:00
gingerBill 25c3fd48f0 Improved ThreadPool implementation 2021-08-26 17:56:28 +01:00
gingerBill e45aa68c14 Remove unneeded +1 for outstanding_task_count 2021-08-26 16:10:32 +01:00
gingerBill 6dfab34aca Merge pull request #1101 from odin-lang/compiler-allocator-improvements
Compiler Allocator Improvements
2021-08-26 16:06:37 +01:00
gingerBill d3d805ffb3 Fix typo 2021-08-26 15:58:34 +01:00
gingerBill 05b9724c85 Correct platform_virtual_memory_init on Unix 2021-08-26 15:55:09 +01:00
gingerBill 5053f0179c Implement virtual memory code for *nix and make generic 2021-08-26 15:53:08 +01:00
gingerBill 3e4d615983 Minor fixes 2021-08-26 15:41:32 +01:00
gingerBill aa8777ee47 Change the implementation of Arena to use virtual memory, and remove the old gbArena code 2021-08-26 15:38:34 +01:00
gingerBill 98dd59e412 Fix return value 2021-08-25 22:28:15 +01:00
gingerBill 7b2f6aaa1c Add [^] to GameControllerGetSensorData 2021-08-25 16:10:39 +01:00
gingerBill ad943f0189 Use [^] on PeepEvents 2021-08-25 15:50:35 +01:00
gingerBill 224496dca7 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-25 15:21:14 +01:00
gingerBill 1ef59417ef Add gl_set_proc_address to both sdl2 and glfw as utility loaders for OpenGL 2021-08-25 15:21:06 +01:00
Jeroen van Rijn 0d5a160409 Add PortMidi to vendor:README.txt. 2021-08-25 13:54:39 +02:00
gingerBill 82facb387c Add vendor:portmidi 2021-08-25 12:46:18 +01:00
gingerBill da7a0df7a1 Simplify logic for parse_binary_expr 2021-08-25 11:43:02 +01:00
gingerBill fcbd94b924 Update enums 2021-08-24 20:05:01 +01:00
gingerBill 5bb3912001 Update licences for GLFW 2021-08-24 20:04:35 +01:00
gingerBill f4248b159d Add vendor:glfw 2021-08-24 20:00:24 +01:00
gingerBill 2e4edcc7e9 Merge pull request #1099 from Kelimion/vendor
vendor: Add `README.md` and clarify licensing.
2021-08-24 18:34:47 +01:00
gingerBill 0d3272d914 Remove ICD from generation 2021-08-24 18:33:35 +01:00
Jeroen van Rijn 50f3e77b43 vendor: Add README.md and clarify licensing. 2021-08-24 19:33:10 +02:00
gingerBill 964d91b855 Add vendor:vulkan 2021-08-24 17:08:03 +01:00
gingerBill bdac3ee120 Add gamecontrollerdb.txt to vendor:sdl
https://github.com/gabomdq/SDL_GameControllerDB
2021-08-24 14:04:27 +01:00
gingerBill b81c670597 Remove debug message 2021-08-24 11:08:41 +01:00
gingerBill 4489df2871 Make sync_t distinct 2021-08-24 00:22:11 +01:00
gingerBill 766c17a6a3 Change [^][1]T usage to [^]T 2021-08-24 00:20:51 +01:00
gingerBill 018f8a82d6 Correct indentation 2021-08-24 00:19:47 +01:00
gingerBill d5a0c004b6 More [^][N]T usage for UniformNuiv 2021-08-24 00:16:39 +01:00
gingerBill 0b6e45c9a2 More [^][N]T usage 2021-08-24 00:15:34 +01:00
gingerBill 5c41f64829 Improve signatures for [^][N*M]T like matrix parameters 2021-08-24 00:14:09 +01:00
gingerBill ad56cf0038 Change some usages of [^]T to ^[N]T where appropriate 2021-08-24 00:06:49 +01:00
gingerBill 58b5e92c2f Update more uses of [^]T types 2021-08-23 23:57:16 +01:00
gingerBill 0a0752db7c Correct int to i32 usage 2021-08-23 23:46:36 +01:00
gingerBill 49fbdd6188 Add more indirect command structs to the procedure calls 2021-08-23 23:45:00 +01:00
gingerBill 1048553e78 More corrections; Add DrawArraysIndirectCommand and DrawElementsIndirectCommand data structures 2021-08-23 23:02:19 +01:00
gingerBill 63282290db Remove dead procedure 2021-08-23 21:42:11 +01:00
gingerBill 7a1498e7dc Remove space prefix 2021-08-23 21:40:17 +01:00
gingerBill 0d3cbb8883 Add vendor:OpenGL
Based off a heavily modified version of: https://github.com/vassvik/odin-gl
2021-08-23 21:33:39 +01:00
gingerBill ce7698c20e Correct core library usage of the new mem.new behaviour 2021-08-23 19:29:01 +01:00
gingerBill 382ca20916 Correct procedure checking flag handling, and correct the (bodge) handle of unchecked procedure bodies 2021-08-23 19:24:53 +01:00
gingerBill fe2ad54f60 Fix bug in check_is_terminating 2021-08-23 17:42:54 +01:00
gingerBill b014879159 Add extra message to assert 2021-08-23 16:45:52 +01:00
gingerBill 81623861c0 Correct mem.clone_slice 2021-08-23 14:33:54 +01:00
gingerBill bd86993035 Remove the old inline and no_inline tokens 2021-08-23 12:37:42 +01:00
gingerBill 4ccf135892 Unify new/make the internal logic between runtime and mem 2021-08-23 12:35:29 +01:00
gingerBill cba0bd30f5 Add suggestions when trying to take the address the a value from a for/switch statement 2021-08-23 11:50:02 +01:00
gingerBill 276d4b8f0d Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-23 11:31:09 +01:00
gingerBill 7bdbaca938 Make SDL_image.Init return InitFlags 2021-08-23 11:31:00 +01:00
Jeroen van Rijn 7f34080b69 Merge pull request #1097 from nakst/master
Thread pool: create threads in thread_pool_wait
2021-08-23 11:17:54 +02:00
nakst 9397555c91 Thread pool: create threads in thread_pool_wait 2021-08-23 10:11:24 +01:00
gingerBill 7a00ef1879 Merge pull request #1096 from nakst/master
thread_pool.cpp: fix with 1 thread; gb.h: remove buggy /proc/cpuinfo code
2021-08-23 09:32:41 +01:00
nakst 35204e3cc5 thread_pool.cpp: fix with 1 thread; gb.h: remove buggy /proc/cpuinfo code 2021-08-23 09:18:18 +01:00
gingerBill daced956e3 Make ThreadPool use std::atomic and heap_allocator() 2021-08-22 23:01:01 +01:00
gingerBill 5a2d582a09 Merge pull request #1095 from nakst/master
Rewrite thread_pool.cpp
2021-08-22 22:55:31 +01:00
nakst b878be6f79 Thread pool fix on Win32 2021-08-22 21:24:56 +01:00
nakst 1f25f60a68 Rewrite thread_pool.cpp 2021-08-22 21:13:41 +01:00
gingerBill 2e921c88fb Add debug information for [^]T 2021-08-22 19:02:52 +01:00
gingerBill abaf8c127d Correct build.bat 2021-08-22 17:12:19 +01:00
gingerBill 0c5fa2cdd5 Fix build.bat 2021-08-22 17:09:40 +01:00
gingerBill 36cb1f868b Embed the SDL2 libraries into vendor:sdl2 2021-08-22 17:05:06 +01:00
gingerBill 037cc679c4 Keep -vet happy 2021-08-22 16:58:12 +01:00
gingerBill db6fad7396 Fix indexing code gen for multi-pointers 2021-08-22 16:55:57 +01:00
gingerBill 07bfb55658 Fix code gen for compare against nil for multi pointers 2021-08-22 16:53:26 +01:00
gingerBill 56078ee099 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-22 16:49:48 +01:00
gingerBill ae4a378294 Merge pull request #1094 from graphitemaster/master
Project all of libc
2021-08-22 16:06:15 +01:00
Dale Weiler 791d7f764b cleanup 2021-08-22 10:05:27 -04:00
Dale Weiler b39a4f3e3b Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-22 09:49:20 -04:00
Dale Weiler 389b50f735 libc projection 2021-08-22 09:48:34 -04:00
gingerBill 2f6e566a32 Remove the deprecated fmt.print*_err procedures 2021-08-22 12:57:08 +01:00
gingerBill d5bad374d9 Remove deprecated procedure slice_ptr_to_bytes 2021-08-22 12:55:57 +01:00
gingerBill 445ed9be2b Use multi-pointers when appropriate 2021-08-22 12:54:04 +01:00
gingerBill 8694a0f68a Update signature_parameter_similar_enough for multi pointers 2021-08-22 12:31:03 +01:00
gingerBill d3fee9d761 Merge pull request #1093 from odin-lang/multi-pointers
Multi Pointers `[^]T`
2021-08-22 11:50:47 +01:00
gingerBill 36a6805b7c Update doc format for multi-pointers 2021-08-22 11:46:26 +01:00
gingerBill 19bf12aa09 Update odin/ast for multi pointers 2021-08-22 11:46:12 +01:00
gingerBill 0decdaed1a Merge branch 'master' into multi-pointers 2021-08-22 11:28:44 +01:00
gingerBill 93b5befe45 Improve error handling for missing semicolon separators in a for loop 2021-08-22 11:27:24 +01:00
gingerBill d72f4a8a79 Correct Multi Pointer Type handling in expressions 2021-08-22 00:59:42 +01:00
gingerBill 91247a8fe1 Fix multi pointers for parapoly 2021-08-21 23:16:30 +01:00
gingerBill 18a0fa02c5 Add multi pointers to core 2021-08-21 23:16:14 +01:00
gingerBill 932f330a51 Add comparisons to LLVM backend for multi pointers 2021-08-21 23:12:15 +01:00
gingerBill 6a77fc4cdd Add multi-pointer types [^]T 2021-08-21 23:10:21 +01:00
gingerBill 01a888fced Update import path 2021-08-21 14:09:48 +01:00
gingerBill f0437a4242 Enforce core:builtin and core:intrinsics for imports 2021-08-21 13:44:16 +01:00
gingerBill 32bdad322a Improve parsing for or_return in core:odin/parser 2021-08-21 13:43:38 +01:00
gingerBill bf130087e7 Change to strings.clone_from_cstring_bounded 2021-08-21 13:43:03 +01:00
gingerBill 38e038a1ab Add strings.clone_from and strings.clone_from_nul_terminated 2021-08-21 13:42:06 +01:00
gingerBill 6504607adf Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-21 13:32:12 +01:00
gingerBill c8378fce95 Add library collection vendor 2021-08-21 13:32:07 +01:00
Jeroen van Rijn 1aeaec8d5c Merge pull request #1091 from Kelimion/win11
os: Add Windows 11 detection.
2021-08-21 14:12:26 +02:00
gingerBill 2aaf927beb Improve error message for Cannot assign value if they have the same name but are from different packages 2021-08-21 13:09:23 +01:00
Jeroen van Rijn bb86b0f526 os: Add Windows 11 detection. 2021-08-21 14:08:22 +02:00
gingerBill 2f5edebefa Rename mem.reinterpret to mem.reinterpret_copy 2021-08-20 10:19:30 +01:00
gingerBill b5cdb331b0 Add mem.reinterpret 2021-08-20 10:18:34 +01:00
gingerBill fa4f3aa7ad Correct atomic usage 2021-08-19 17:51:19 +01:00
gingerBill a90fe7211c Make global_entity_id atomic 2021-08-19 17:44:26 +01:00
gingerBill ac6cc5191a Make ThreadPool.is_running atomic 2021-08-19 17:43:15 +01:00
gingerBill 38841dd46e Fix race condition from add_entity_use due to Entity.identifier 2021-08-19 17:38:18 +01:00
gingerBill e722af7f61 Remove unneeded disabled warnings from build.bat 2021-08-19 15:43:51 +01:00
gingerBill df372dbd5b Migrate and remove more from gb.h 2021-08-19 15:38:21 +01:00
gingerBill 5c4d95d539 Move more of gb.h's Synchronization code into common.cpp 2021-08-19 15:19:36 +01:00
gingerBill 9ae4de2ab8 Remove unused code from gb.h (which means it is heavily modified now) 2021-08-19 15:09:39 +01:00
gingerBill 7845769d4b Remove unused code 2021-08-19 15:03:10 +01:00
gingerBill 33239324b8 Improve the C++ to be more correct for clang on Windows, still requiring the same disabled warnings as on *nix 2021-08-19 14:44:53 +01:00
gingerBill 82a74ebfa9 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-19 11:40:32 +01:00
gingerBill 35026000bb Fix deadlock caused by typo 2021-08-19 11:40:26 +01:00
Jeroen van Rijn 55cf3d26bf Merge pull request #1090 from Kelimion/bigint
big: Update license to BSD-3.
2021-08-19 12:13:39 +02:00
Jeroen van Rijn 23d29be4d8 big: Update license to BSD-3. 2021-08-19 12:12:59 +02:00
Jeroen van Rijn 1ad0743a52 big: Nicely align test suite results. 2021-08-19 12:12:59 +02:00
gingerBill 54af47a138 Remove useless code 2021-08-18 23:38:06 +01:00
gingerBill b84ee3ab8f Fix odin test not executing any tests 2021-08-18 23:33:27 +01:00
gingerBill e023b96737 Remove json import from demo 2021-08-18 22:33:18 +01:00
gingerBill 3fde4616e0 Correct mutex usage for path_to_fullpath; make ThreadPool use BlockingMutex 2021-08-18 21:21:30 +01:00
Mikkel Hjortshøj 4812006eb8 Update ci.yml 2021-08-18 22:09:44 +02:00
gingerBill 740995df3d Remove attribute parameter for pthread_mutex_init 2021-08-18 21:07:06 +01:00
gingerBill aa5c3da414 Make BlockingMutex non-recursive on *nix systems 2021-08-18 20:57:03 +01:00
gingerBill d419d81841 Remove unused code 2021-08-18 20:48:26 +01:00
gingerBill 08942714a2 Make Arena allocate virtual memory directory; make it use a BlockingMutex 2021-08-18 20:46:10 +01:00
gingerBill 3c443babb2 Extra sanity check around static 2021-08-18 20:32:54 +01:00
gingerBill 326e5cd046 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-18 20:31:39 +01:00
gingerBill 79e98b71d3 Remove dead code, and add an extra mutex 2021-08-18 20:31:34 +01:00
Jeroen van Rijn 96605f700b Merge pull request #1089 from Kelimion/bigint
big: Enable Toom again.
2021-08-18 15:36:45 +02:00
Jeroen van Rijn 38b5e01343 Merge branch 'master' into bigint 2021-08-18 15:35:49 +02:00
Jeroen van Rijn 06cde91ba3 big: Enable Toom again. 2021-08-18 15:35:01 +02:00
Jeroen van Rijn 3891d6a483 Merge pull request #1088 from Kelimion/bigint
big: Fix signed multiplication for some inputs.
2021-08-18 15:32:49 +02:00
Jeroen van Rijn 5fd7a5f32a big: Fix signed multiplication for some inputs. 2021-08-18 15:24:43 +02:00
gingerBill a01c946c20 Add mutex to Scope lookups and insertions 2021-08-18 11:17:14 +01:00
gingerBill 84b0da44db Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-17 19:54:17 +01:00
gingerBill cdb3a5205c Add mutex for add_type_and_value 2021-08-17 19:54:09 +01:00
Jeroen van Rijn eae98feb7a Merge pull request #1086 from Kelimion/bigint
big: Temporarily disable Toom.
2021-08-16 22:19:10 +02:00
Jeroen van Rijn 3af078e941 Merge branch 'master' into bigint 2021-08-16 22:16:03 +02:00
Jeroen van Rijn 48c1f0ab59 big: Disable Toom for a moment. 2021-08-16 22:13:54 +02:00
Jeroen van Rijn 19386814b3 Merge pull request #1085 from Kelimion/bigint
Add `_private_int_mul_toom` + `_private_int_mul_karatsuba`.
2021-08-16 21:29:40 +02:00
Jeroen van Rijn 706e58c1c7 big: Add _private_int_mul_toom`. 2021-08-16 21:17:21 +02:00
gingerBill 9ab94650c8 Allow + in import paths 2021-08-16 18:21:58 +01:00
gingerBill fce86ff3d5 Correct struct tag bug 2021-08-16 18:17:26 +01:00
gingerBill 0051cd12e2 Make flags atomic for Entity and Type 2021-08-16 16:30:49 +01:00
gingerBill df159dbae7 Add some missing files to sync2 for linux and darwin 2021-08-16 15:48:54 +01:00
gingerBill 94d298755a Fix race condition when adding a dependency 2021-08-16 15:33:26 +01:00
Jeroen van Rijn 8b49bbb0fc big: Add _private_mul_karatsuba. 2021-08-16 16:10:10 +02:00
gingerBill 5f072591ba Merge pull request #1082 from odin-lang/or_else-or_return-operator
`or_else` and `or_return` operators
2021-08-16 12:03:43 +01:00
gingerBill e3fef2dade Improve parsing for or_return; allow #force_inline foo() or_return; 2021-08-16 11:58:50 +01:00
gingerBill 4c306a6f99 Correct or_return logic for debug printing and expression is not used checking 2021-08-16 11:08:37 +01:00
gingerBill 0996cc82a7 Keep -vet happy 2021-08-15 23:17:12 +01:00
gingerBill f293d7c997 Update package encoding/json for or_return 2021-08-15 23:11:15 +01:00
gingerBill b2097604d5 Add clone_ast for or_else and or_return 2021-08-15 23:10:52 +01:00
gingerBill 4e1c9b71f4 Update core:odin/* for or_else and or_return 2021-08-15 19:05:55 +01:00
gingerBill 3e2788afdc Add extra example to or_return_operator 2021-08-15 18:51:20 +01:00
gingerBill 1a7f508dd9 Improve comment 2021-08-15 18:44:50 +01:00
gingerBill dc8cfcf92a Fix typos and improve clarity of or_return_operator 2021-08-15 18:36:34 +01:00
gingerBill ac08d37ca0 Add or_return_operator to examples/demo 2021-08-15 18:29:49 +01:00
gingerBill 4035fec784 Add more uses of or_return 2021-08-15 18:13:56 +01:00
gingerBill b071a07c86 Replace uses of err != nil with or_return where appropriate 2021-08-15 17:56:24 +01:00
gingerBill c27b8a71fd Replace err != nil with or_return where appropriate 2021-08-15 17:52:10 +01:00
gingerBill b8661e0ae0 Update semi-colon insertion rules for or_return 2021-08-15 17:16:37 +01:00
gingerBill 21cbac755e Make or_else and or_return operators (binary and suffix respectively) 2021-08-15 17:14:35 +01:00
gingerBill a3a20f09e2 or_return built-in procedure 2021-08-15 16:55:30 +01:00
gingerBill d62f189d72 Remove some dead code 2021-08-15 15:09:47 +01:00
gingerBill 84713b58e0 Improve error handling for field list prefixes 2021-08-15 13:29:44 +01:00
gingerBill 294c8426e6 Minor clean up of parse_field_prefixes 2021-08-15 13:18:06 +01:00
gingerBill 7bbc9a4634 Add #any_int directive to replace auto_cast uses on parameters. 2021-08-15 12:56:59 +01:00
gingerBill 1cd3b693ae Update LICENSE 2021-08-15 12:12:48 +01:00
gingerBill d1b9b06614 Add core:math/big to examples/all 2021-08-15 11:14:51 +01:00
gingerBill 19aefa6a40 Add assignment statement to #no_bounds_check etc rules. Correct os_linux.odin usage. 2021-08-15 11:14:34 +01:00
gingerBill effecf8595 Fix typo 2021-08-15 11:13:59 +01:00
gingerBill d5e3f72a0b Define where #bounds_check/#no_bounds_check can be applied 2021-08-15 11:09:41 +01:00
gingerBill 9fb486b2ad Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-15 11:08:35 +01:00
gingerBill d70fa4329c Move #no_bounds_check to before return 2021-08-15 11:08:28 +01:00
Jeroen van Rijn 3f29a0d6dd Merge pull request #1078 from Kelimion/bigint
Add recursive division.
2021-08-14 15:58:27 +02:00
Jeroen van Rijn 0db86a0638 big: Add workaround for DLL globals bug. 2021-08-14 13:51:17 +02:00
Jeroen van Rijn dc02566a84 big: Add _private_int_div_recursive. 2021-08-13 23:45:00 +02:00
gingerBill 0e84e06756 Fix lower and upper values for a bit_set[Enum] type. 2021-08-13 14:17:27 +01:00
gingerBill e6b2df4b2b Add extra error message check to lb_big_int_to_llvm 2021-08-13 14:16:53 +01:00
Jeroen van Rijn 37be8d4091 big: Add internal_invmod. 2021-08-13 14:55:53 +02:00
gingerBill a3930cb470 Improve fmt._user_formatters logic 2021-08-13 12:44:55 +01:00
gingerBill ad402726f1 Fix #1026 2021-08-13 12:21:14 +01:00
gingerBill 8ff9f2e44f Fix #1077 2021-08-13 11:49:52 +01:00
gingerBill 799a56bbcb Fix column in tokenizer (due to removed line) 2021-08-13 10:50:05 +01:00
gingerBill fbbd43a6d8 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-13 10:45:35 +01:00
gingerBill 367bf0c7ae Fix #1076 2021-08-13 10:45:29 +01:00
Jeroen van Rijn f72a0de074 big: Add inverse mod. 2021-08-13 01:41:33 +02:00
Jeroen van Rijn 07baae04c9 Merge pull request #1075 from Kelimion/bigint
Add `core:math/big`, an arbitrary precision library.
2021-08-11 21:43:54 +02:00
Jeroen van Rijn eb22a49b02 big: Add int_from_bytes_*. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn ee24f2dd37 big: Improve int_to_bytes_*. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 12f9b6db63 big: Add int_to_bytes_{big, little} + Python compatible variants. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 851780b8f4 big: Add arguments and usage to test.py. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 5f34ff9f9f big: Add _private_int_sqr_toom. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 2b274fefbb big: Add _private_int_sqr_karatsuba. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 6c681b258c big: Add _private_int_sqr_comba. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 1f91a2fe65 big: Finish refactor. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 19ff27788c big: Refactoring. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn 1ebb0bd9d6 big: More refactoring. 2021-08-11 20:59:54 +02:00
Jeroen van Rijn d505a05d36 big: More refactoring. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 07dca737f0 big: More refactoring. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 6d34a8344a big: Refactor helpers. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 40b7b9ecdf big: Refactor exponents and such. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 53bf66ce1e big: Prettify internal_cmp_digit. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn fd95f50c56 big: Split up int_is_* comparison tests. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 777e17d80f big: Improve tunables. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn d4a03acbc3 big: Split up int_mod_bits (res = val % (1 << bits)) 2021-08-11 20:59:53 +02:00
Jeroen van Rijn c3db24f834 big: Split up gcd + lcm. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 62dcccd7ef big: Move division internals. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn e288a563e1 big: Move _mul private functions. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 6298226238 big: Switch choose over to internal implementations. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 9321616c80 big: Split more into public and internal. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 9890e7cfeb big: Improved zero_unused helper. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 4be48973ad big: Squashed shl1 bug when a larger dest was reused for a smaller result. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn f8442e0524 big: Split up mul into internal and public parts. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 9858989b1c big: Split up add and sub into public and internal parts. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 511057ca36 big: Improve timing code. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 35d8976de4 bit: Optimized int_bitfield_extract. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 463003e86a bit: Improved bitfield extraction. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 85a2a8815e big: Some more work on constants. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 47397a6a48 Add faster divison. 2021-08-11 20:59:53 +02:00
Jeroen van Rijn 2323ca1622 big: Add MATH_BIG_FORCE_64/32_BIT flags. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn fc0a92f8ac big: Add constants. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 97d80d03f9 big: Error.None -> nil 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 627872db97 big: Timed factorial. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn a27612ec6a Add _mul_comba path. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 491e4ecc74 big: Add binary split factorial. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn cd0ce7b76e big: Add choose. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 320387c4ee big: Add gcd_lcm fast path in wrapper. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 6424a5a8dd big: Refactored gcm and lcm to use a common function. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 06f5a6c785 big: Special case gcd(0,0) + lcm(0,0). 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 8b1d8c8453 big: Add lcm and its test. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 0028cb0258 big: Test gcd. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn b15ee059ad big: Add gcd. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 50feeaa285 big: Add test for factorial. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn e80ac18324 big: Add factorial, have tests use hex strings. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn db0196abc7 big: Test root_n. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 149c7b88df big: Fix sqrt, div, add with certain inputs. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 7afd1b15a8 big: test_pow for larger ints. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn f12672727d big: Add test_pow and some more switches. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 2179cc2bc7 big: Improved test driver. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 961adfedd9 big: Test negative inputs as well. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 385b9c9922 big: Add tests for log. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 922df6a438 big: Add more exhaustive tests. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn c1a001c331 big: Add randomized testing. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 13fab36639 big: Fix mul. 2021-08-11 20:59:52 +02:00
Jeroen van Rijn 708389a7ee big: Improve test driver. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn fb6c9af1ae big: Improve tests. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 85aa4dd670 big: Start test suite. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 74258a170a big: fix itoa base PoT other than 16. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 2fbff25a18 big: Improve int_bitfield_extract. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 9c150381bf big: Add rand. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 531c4936dd big: Add root_n. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 2aae1016ab big: Add sqrt. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 9c2468ecf7 big: Add atoi. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 0a431eef19 big: Add another way to estimate radix size. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 9646d1f2b8 big: Add submod, mulmod, sqrmod. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 5f7aeb3045 big: Add mod and addmod. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 1ebaa9fb3b big: itoa now works for arbitrary radixes. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn c2255c6c19 big: Add div. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 2884fa5506 big: add div by 3. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 31c94bd7f8 big: Finish log, fix sqr. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 5f63e3952e big: Correct pow bugs from the original. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn d953e40fb3 big: Add pow. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn c3a4d7dda2 big: Fast square method. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn b4a29844e9 big: Add multiplication. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 0254057f1b big: Add swap. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn f34ba44bf8 big: Add shl, shr and shrmod. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn d4d863c4db big: Add mod_power_of_two. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 78c0877994 big: Add get(a, type) and get_float. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 1d0b37c1d8 big: add shl1, shr1. 2021-08-11 20:59:51 +02:00
Jeroen van Rijn 7648f2e655 big: Finish big ZII refactor. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn d9efa6c8b5 big: More ZII refactoring. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 2e372b33a3 big: More ZII refactoring. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 687c211a58 big: ZII. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 4eadd0867d big: Continuing to refactor. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 9dba17cf87 bigint: refactor to big.Int instead of bigint.Int. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn baef0c291d bigint: Added some more helpers. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn cccd290834 bigint: Add is_power_of_two helper. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 5af85aed3d bigint: itoa support for arbitrary precision if is_power_of_two(radix) 2021-08-11 20:59:50 +02:00
Jeroen van Rijn e600e5947b bigint: remove unnecessary boundary checks. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn d7ae611f76 bigint: itoa now writes backwards directly, no need to reverse after. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 04a83eb9f7 bigint: pass size to itoa_raw. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 341e8a3c99 bigint: itoa works for numbers <= 120 bits. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn e3d8ac559d bigint: Fast paths for radix code. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 767948ab46 bigint: log_n for bases that fit within one DIGIT or are a power of two. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn dbcd8da733 bigint: Working on itoa and logn. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 905d5459a9 bigint: Add count_bits and more prep. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn dfd5a993a2 bigint: Prepare for multiplication. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn daceaa65f5 bigint: Add substractin with immediate. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn c2c07f07db Add single DIGIT addition. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn c5cbd3260a bigint: Add prototypes for immediate add+sub. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn d57e1be89f bigint: Improve add. 2021-08-11 20:59:50 +02:00
Jeroen van Rijn 18dda6ff9d Start of core:math/bigint
We have:
- `init` to create a new `Int`
- `init(from_integer)` to create a new `Int` and set it to `from_integer`.
- `set(Int, from_integer)` to set an `Int` to `from_integer`
- `add(dest, a, b)` to add `a` and `b` into `dest`.
- `sub(dest, a, b)` to subtract `b` from `a` and put the result in `dest`.

And a few helper functions, like:
- `is_zero`, `is_negative`, ...
- `grow`, `shrink`, `clear`, `zero`
2021-08-11 20:59:50 +02:00
gingerBill 7afc367275 Update examples/all/all_main.odin 2021-08-11 19:11:00 +01:00
gingerBill c465171b45 Fix #1061 2021-08-09 21:41:19 +01:00
gingerBill 02f22a0b3f Correct DllMain behaviour 2021-08-09 21:23:24 +01:00
gingerBill 193fd0eecb Correct and improve type inference for swizzling expressions 2021-08-09 20:13:58 +01:00
gingerBill 01f431b01f Unify semantics of the built-in swizzle procedure with the selector expression semantics e.g. .xyz 2021-08-09 19:37:58 +01:00
gingerBill aebfa4b28e Allow len and cap to return a uint if a type hint is uint to aid people wanting to use unsigned integers 2021-08-09 17:39:38 +01:00
gingerBill a3abe991a4 Add package core:encoding/hxa 2021-08-09 16:26:51 +01:00
gingerBill e793f92e67 Improve parsing handling for the { return } cases 2021-08-09 13:01:47 +01:00
gingerBill 042f376626 Minor code changes to Map/StringMap 2021-08-09 13:01:26 +01:00
gingerBill d99ed692ba Add utility procedures: io.read_ptr; io.write_ptr; io.read_ptr_at; io.write_ptr_at 2021-08-09 12:33:21 +01:00
gingerBill 4d00c2b800 Allocator_Error.Mode_Not_Implemented; Minor improvement to map runtime procedures 2021-08-08 14:29:45 +01:00
gingerBill a5605e94b1 Simplify Map and StringMap in the compiler to reuse the hashes' array data if possible. 2021-08-08 13:56:40 +01:00
gingerBill 9cfe20cfb4 Correct error message for add_import_dependency_node 2021-08-08 13:13:31 +01:00
gingerBill db3501f61b [Breaking] Change the layout json.Value to be a union rather than a struct of a json.Pos and the union 2021-08-08 12:59:35 +01:00
gingerBill 48538aa792 Remove package core:encoding/cel 2021-08-08 12:50:38 +01:00
gingerBill 5fd64f48ee Minor procedure rename 2021-08-08 12:48:44 +01:00
gingerBill a3b7126875 Simplify init_tokenizer_with_data 2021-08-08 12:47:45 +01:00
gingerBill 5756c8a7c6 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-08-08 12:45:33 +01:00
gingerBill cdd0061869 Prefer ..= over .. 2021-08-08 12:45:27 +01:00
Mikkel Hjortshøj e6adfd8054 Update create_nightly_json.py 2021-08-08 11:29:56 +02:00
Jeroen van Rijn 6d59223efd Merge pull request #1072 from Kelimion/cel_fix_ise
CEL: Fix by changing `using enum` to ISE.
2021-08-08 02:21:04 +02:00
Jeroen van Rijn ebd034fff9 CEL: Fix ISE. 2021-08-08 02:19:32 +02:00
gingerBill 000bda8419 Reduce superfluous error messages for return statements expecting not-1 return values 2021-08-07 16:29:00 +01:00
gingerBill 423b842347 Fix typo 2021-08-07 15:07:29 +01:00
gingerBill 16eeae36d7 Inline heap_allocator resize logic on *nix platforms 2021-08-07 15:05:46 +01:00
gingerBill 5453e92bcb Minor test on array_set_capacity 2021-08-07 14:44:48 +01:00
gingerBill c16c9535d9 Reorder ci.yml from run check version to version check run 2021-08-07 14:40:54 +01:00
gingerBill 662c7b1e71 Minor clean-up 2021-08-07 14:39:26 +01:00
gingerBill 571170fd30 Improve and simplify the memory layout of MPMCQueue 2021-08-07 14:25:48 +01:00
gingerBill 911c428dac Remove dead code in queue.cpp; clean up initialization code 2021-08-07 13:54:08 +01:00
gingerBill 40822be595 Reorganize llvm_backend.cpp into separate files for easier maintenance 2021-08-07 12:01:48 +01:00
gingerBill f5e51a29b5 Fix #1070 2021-08-07 11:23:40 +01:00
gingerBill beaad719ad Reallow using on enum declarations temporarily but with a warning. 2021-08-05 17:51:45 +01:00
gingerBill 0d257c61cd Disallow using on an enum declaration. 2021-08-05 17:46:42 +01:00
gingerBill dd8fa1d690 Prefer ..= over .. 2021-08-04 00:36:10 +01:00
gingerBill af6df7d7c9 Improve error cases in core:odin/parser 2021-08-04 00:23:31 +01:00
gingerBill 57a17a708b Improve core:odin/parser 2021-08-04 00:10:41 +01:00
gingerBill 1f79082921 Remove dead comments 2021-08-04 00:10:05 +01:00
gingerBill afff9478c8 Make core:odin/tokenizer be consistent with the compiler's version 2021-08-03 23:27:26 +01:00
gingerBill b352b42afc Remove old comment 2021-08-03 16:31:50 +01:00
gingerBill c3e4509d17 Improve error message when using a comma rather than a semicolon in a bit_set 2021-08-03 15:46:14 +01:00
gingerBill 664be28941 Fix typo 2021-08-03 15:45:32 +01:00
gingerBill d7e970ac32 Add extra debugf message for generate missing procedure 2021-08-03 14:36:15 +01:00
gingerBill 810dcfc602 Remove debug gb_printf_err and replace with debugf 2021-08-03 14:30:32 +01:00
gingerBill 14645b147f Reorganize missing_procedures_to_check generation code 2021-08-03 14:17:39 +01:00
gingerBill b036cc9013 Add missing_procedures_to_check to lbModule 2021-08-03 14:13:38 +01:00
gingerBill 3a8ac92995 Add sanity check in lb_create_procedure 2021-08-03 13:49:01 +01:00
gingerBill 67bedcba4b Reorganize stages in checker 2021-08-03 13:41:28 +01:00
gingerBill 4987ef89f1 Reorganize some of the checker stages 2021-08-03 13:40:47 +01:00
gingerBill 545b345eea Remove optimizations in tokenizer and default to older code (same logic) (optimize later) 2021-08-03 13:33:01 +01:00
gingerBill 3e961af5f1 Sort files by name in packages 2021-08-02 22:55:22 +01:00
gingerBill 9e6e769141 Add sanity checks to checker 2021-08-02 18:32:17 +01:00
Jeroen van Rijn c0f746a251 Merge pull request #1065 from Kelimion/string_cut
Add `strings.cut`, which returns a substring.
2021-08-02 18:09:59 +02:00
gingerBill ccbdf086ff Add @(warning=<string>) 2021-08-02 16:58:50 +01:00
Jeroen van Rijn d260ca6738 string.cut uses context.allocator by default. 2021-08-02 17:58:42 +02:00
gingerBill b0e64ca7e8 Prepare tokenizer for optimizations 2021-08-02 16:47:32 +01:00
gingerBill 7f3d4cb504 Remove the literal conversion logic to the parser from the tokenizer 2021-08-02 00:53:45 +01:00
gingerBill 97be36d18a Replace line with column_minus_one in Tokenizer; Remove dead code 2021-08-02 00:26:54 +01:00
gingerBill be76da2c90 Begin optimizing tokenizer; Replace gb_utf8_decode with utf8_decode (CC but easier to change later) 2021-08-01 23:56:17 +01:00
gingerBill b1a8357f50 Clean up a bit of the tokenizer code so that the semicolon insertion rules are in one place 2021-08-01 22:41:00 +01:00
Jeroen van Rijn 0dc900ba34 Add strings.cut, which returns a substring. 2021-08-01 19:41:20 +02:00
gingerBill 700624119b Give begin_error_block its own recursive mutex 2021-07-29 12:35:11 +01:00
gingerBill af32aba7fc Modify MPMCQueue behaviour to use i32 over isize; Correct cache line padding within MPMCQueue 2021-07-28 00:59:30 +01:00
gingerBill 541c79c01a Add mutex for @(builtin) attributes 2021-07-28 00:27:16 +01:00
gingerBill 358226468d EXPERIMENT: Set DEFAULT_TO_THREADED_CHECKER on all platforms 2021-07-27 23:55:55 +01:00
gingerBill d1e5f34f76 Use DEFAULT_TO_THREADED_CHECKER 2021-07-27 23:55:19 +01:00
gingerBill 416dd93bf7 Add accidentally removed call 2021-07-27 23:39:35 +01:00
gingerBill 7c80577160 Correct race condition on untyped expr info map logic on global evaluations 2021-07-27 23:37:55 +01:00
gingerBill a5d6fda433 Define which mutexes are blocking and recursive explicitly 2021-07-27 23:14:01 +01:00
gingerBill 4bc3796f9b Short circuit check_with_workers logic on worker_count == 0 2021-07-27 23:00:51 +01:00
gingerBill 5e12f5a746 Unify threading logic 2021-07-27 22:55:32 +01:00
gingerBill 4080ba4026 Remove global semaphore and place in CheckerInfo 2021-07-27 21:42:43 +01:00
gingerBill e17593be94 Remove dead mutex 2021-07-27 21:14:06 +01:00
gingerBill 44aa69748c Correct logic for check_import_entities - collect file decls 2021-07-27 21:13:03 +01:00
gingerBill 9cd5ea59dd Big simplification and improvement of the entity collection system, reducing unneeded steps for packages 2021-07-27 20:45:50 +01:00
gingerBill 116e98b378 Improve default scope size 2021-07-27 10:59:39 +01:00
gingerBill ae25787f48 Fix syntax error for a missing package name 2021-07-26 11:43:17 +01:00
gingerBill 08dc829b70 Manually short circuit in lb_build_if_stmt for constant conditions 2021-07-26 10:59:07 +01:00
gingerBill 3ac674cf02 Fix typo 2021-07-25 13:12:09 +01:00
gingerBill 6cd06ab95f Minor fix 2021-07-25 13:07:31 +01:00
gingerBill 99080d41f3 INTERNAL USE ONLY: //+lazy build flag 2021-07-25 13:06:09 +01:00
gingerBill 92f3567ee6 Default to using a threaded checker on Windows; Add -no-threaded-checker for Windows 2021-07-24 18:00:19 +01:00
Jeroen van Rijn 481fc8a5b6 Merge pull request #1060 from Kelimion/win_sys
Allow `core:sys/windows` to build on Windows only
2021-07-15 12:15:10 +02:00
Jeroen van Rijn 5dfff51a40 Allow core:sys/windows to build on Windows only 2021-07-15 12:13:57 +02:00
gingerBill 2938ec028f Remove dead code 2021-07-15 00:37:59 +01:00
gingerBill 981b9fb7a8 Remove need for scope mutex, make Scope singly linked list tree with atomic pointers 2021-07-14 23:49:35 +01:00
gingerBill 10f4d8df32 Override libtommath allocation procedures 2021-07-14 23:36:23 +01:00
gingerBill e15858e2be Remove random load balancing in thread_proc_body 2021-07-14 22:53:02 +01:00
gingerBill 6d8302825c Add Greed Work Stealing and Random Load Balancing for check_procedure_bodies 2021-07-14 01:13:39 +01:00
gingerBill fae8bf96dd Muilthread check_collect_entities_all 2021-07-14 00:46:03 +01:00
gingerBill bc59dc6389 Remove duplicate code 2021-07-14 00:36:48 +01:00
gingerBill bd8e2f82be Replace non-recursive mutexes with BlockingMutex; Minor improves to initialization improves 2021-07-14 00:34:34 +01:00
gingerBill 69027b6840 Remove dead mutexes 2021-07-13 23:10:12 +01:00
gingerBill 7a9b7af078 Reduce mutex usage and convert things to queues from arrays 2021-07-13 23:09:24 +01:00
gingerBill 31c7afce1b Minor code clean up to reuse the ProcInfo consumption code 2021-07-13 21:19:13 +01:00
gingerBill bab1873416 Require throughput pass results with -show-more-timings -show-debug-messages rather than just the former flag 2021-07-13 18:39:11 +01:00
gingerBill 5e2950e9fb Move asserts around 2021-07-13 18:35:23 +01:00
gingerBill 74c019f271 Correct lb_big_int_to_llvm 2021-07-13 18:32:53 +01:00
gingerBill a745bb8f42 Add extra message to assert 2021-07-13 18:21:53 +01:00
gingerBill da9870c77d Do manual byte swapping for endianness in lb_big_int_to_llvm 2021-07-13 18:15:47 +01:00
gingerBill 698eeaf7c3 Add (internal flag) -show-debug-messages 2021-07-13 17:40:06 +01:00
gingerBill bd954d9990 Minor code reorganization 2021-07-13 17:28:39 +01:00
gingerBill 4ded42a33b Split up cycle check and adding type info timings 2021-07-13 17:24:20 +01:00
gingerBill 1877965ac3 Short on -threaded-checker 2021-07-13 17:04:08 +01:00
gingerBill cec2309504 Big improvement to the -threaded-checker code, unifying the logic and simplify behaviour 2021-07-13 16:58:40 +01:00
gingerBill ed5a4afc8c Temporarily disable -threaded-checker; Restructure the untyped-expr-info system to be much more thread-friendly 2021-07-13 15:54:56 +01:00
gingerBill f29b51efdd Fix gb_shuffle 2021-07-13 13:09:55 +01:00
gingerBill 3930a32b0c enum Addressing_Mode : u8; 2021-07-12 16:45:54 +01:00
gingerBill 76707e1d2f Add sanity casts for 32/64 bit correctness 2021-07-12 11:03:12 +01:00
gingerBill ff2e5c3efe Simplify big_int_not for negative inputs 2021-07-11 17:43:56 +01:00
gingerBill 3600b2e209 Merge pull request #1057 from odin-lang/new-big-int-library-integration
New Big Int Library Integration
2021-07-11 17:20:57 +01:00
gingerBill eb36a0f3b1 Remove dead file 2021-07-11 16:35:04 +01:00
gingerBill b397254696 Rename libtommath.c to libtommath.cpp 2021-07-11 16:33:58 +01:00
gingerBill 9a37d3b6e5 Add -Wno-unused-value 2021-07-11 16:29:51 +01:00
gingerBill 51c4a19234 Fix tab and space issue in Makefile
FUCK DO I HATE Makefile whitespace sensitivity between spaces and tabs
2021-07-11 16:26:21 +01:00
gingerBill a1a1668dcf Update build.bat and Makefile 2021-07-11 16:23:25 +01:00
gingerBill e308098f18 Add libtommath.c 2021-07-11 16:19:20 +01:00
gingerBill 63b572a0ab Clean up big int to LLVM integer code 2021-07-11 16:18:30 +01:00
gingerBill e90e7d4af9 Change mp_clear calls to big_int_dealloc 2021-07-11 16:10:04 +01:00
gingerBill 460e14e586 Change the compiler's big integer library to use libTomMath
This now replaces Bill's crappy big int implementation
2021-07-11 16:08:16 +01:00
gingerBill ebcabb8a27 Add sanity conversion check for integer to quaternion 2021-07-11 00:51:56 +01:00
gingerBill 257b749e9d Minimize mutex usage in update_expr_type 2021-07-11 00:21:31 +01:00
gingerBill d9e6ade030 Add experimental support for a threaded semantic checker to -threaded-checker 2021-07-10 23:51:37 +01:00
gingerBill 690374d4de Fix typo 2021-07-10 23:07:42 +01:00
gingerBill adb25d9d19 Convert constant tag to the correct type for LLVMAddCase 2021-07-10 22:29:52 +01:00
gingerBill 2949e4b0c7 Fix floattidf typo 2021-07-10 22:23:22 +01:00
gingerBill 6de0181c75 Minor improvements to Map and StringMap 2021-07-10 21:51:39 +01:00
gingerBill 8a6b743d2a Simplify thread_pool_wait_to_process 2021-07-10 21:50:19 +01:00
gingerBill ed8a6f872d Move things around for sanity checking for multithread preparation 2021-07-10 21:29:49 +01:00
gingerBill 0a61d4bf2b Use next_pow2_isize 2021-07-10 19:57:54 +01:00
gingerBill 332461c0d2 Add prototypes for next_pow2 2021-07-10 19:52:26 +01:00
gingerBill d8abe7fc4d Implement MPMCQueue for procedure body checking
This is preparation for basic multithreading in the semantic checker
2021-07-10 19:50:34 +01:00
gingerBill ec9667ef5a Remove debug code 2021-07-10 17:11:54 +01:00
gingerBill 9f7154a039 Prepare for multithreading the semantic checker by giving mutexes to variables of contention
NOTE(bill): I know this is dodgy, but I want to make sure it is correct logic before improve those data structures
2021-07-10 15:14:25 +01:00
gingerBill 4a932616fc Improve CheckerContext usage 2021-07-10 13:02:13 +01:00
gingerBill 73fe36f19c Remove dead variable 2021-07-10 11:59:41 +01:00
gingerBill 4167ae95ae Fix #1050 2021-07-10 11:48:28 +01:00
gingerBill 13c3c5be95 Fix #1028 2021-07-10 11:46:22 +01:00
gingerBill 3afec0bcbe Fix #1054 2021-07-10 11:42:21 +01:00
gingerBill 8b1bfc80fb Fix #1051 2021-07-10 11:27:38 +01:00
gingerBill 3662275119 Allow x in ptr_to_map_or_bit_set 2021-07-10 11:18:19 +01:00
gingerBill 141573c18c Enable Damerau-Levenshtein 2021-07-10 11:09:24 +01:00
gingerBill e692efbe09 Improve update expr type semantics for ternary expressions 2021-07-10 11:08:51 +01:00
gingerBill f6c1a5bf6e Merge branch 'master' of https://github.com/odin-lang/Odin 2021-07-09 15:33:30 +01:00
gingerBill 6afc28f827 Use builtin.min and builtin.max in package slice 2021-07-09 15:33:25 +01:00
gingerBill df6681ad4e Merge pull request #1055 from streof/fix-typos-container-package
Fix typos container package
2021-07-09 13:27:03 +01:00
streof 114efbc57c Fix error: Cannot assign to a procedure parameter 2021-07-09 14:03:49 +02:00
streof 2c71494ad1 Fix error: Undeclared name: p 2021-07-09 13:54:27 +02:00
gingerBill 35230b1a11 Add "Suggestion: Did you mean?" for selector expression typos 2021-07-08 23:15:07 +01:00
gingerBill 7acbf8b7b9 Add slice.min and add slice.max 2021-07-08 11:23:07 +01:00
gingerBill f7413ca974 Fix thread_unix.odin 2021-07-05 16:36:07 +01:00
gingerBill 9b3a0251ca Use or_else in the core library when it makes sense 2021-07-05 16:33:01 +01:00
gingerBill 3b9ca8535f Fix comments 2021-07-05 16:26:11 +01:00
gingerBill a98eee145d Remove try; Replace try x else y with or_else(x, y) 2021-07-05 16:23:13 +01:00
gingerBill c6b9b3b9a4 Fix try parsing for expression statements 2021-07-04 22:52:12 +01:00
gingerBill a4be1a5e4c delete_key now returns the deleted key and deleted value (if found) 2021-07-04 18:52:47 +01:00
gingerBill ee908c00de Add documentation for the overview of package fmt 2021-07-04 18:21:41 +01:00
gingerBill 46264032aa Improve error messages for try expressions 2021-07-04 12:50:44 +01:00
gingerBill 4b831dbddd Try try and or_else built-in procedures with operators try and try else 2021-07-04 12:37:21 +01:00
gingerBill a01d6dcea7 Refactor return logic to be more reusable with lb_emit_try 2021-07-04 01:57:38 +01:00
gingerBill 01a15f78e6 Simplify lb_emit_try return logic 2021-07-04 01:50:37 +01:00
gingerBill 5f71c41582 Fix lb_emit_try 2021-07-04 01:47:43 +01:00
gingerBill e8f2c5a48a [Experimental] Add 'try' and `or_else' built-in procedures 2021-07-04 01:38:43 +01:00
gingerBill 1c76577918 Add slice.sort_by_cmp Ordering based sorting algorithms 2021-07-03 15:16:44 +01:00
gingerBill 4285b58aaa Add #no_bounds_check to linalg procedures 2021-07-03 14:38:41 +01:00
gingerBill 9cc366de97 Be more consistent with runtime intrinsics usage 2021-07-03 14:38:15 +01:00
gingerBill 212d294b84 Deprecate sort.slice and sort.reverse_slice 2021-07-03 14:37:55 +01:00
gingerBill d6125f05d4 Correct does_field_type_allow_using 2021-06-29 12:35:15 +01:00
gingerBill ad22eda87c Improve linalg.transpose type determination for square matrices 2021-06-28 13:23:28 +01:00
gingerBill 8d31ba492d Fix #1042 2021-06-28 11:32:23 +01:00
gingerBill 8f611b3399 Fix #1043 2021-06-28 11:21:03 +01:00
gingerBill 618f858930 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-06-28 11:06:00 +01:00
gingerBill 185277a2b6 Fix swizzling of pointers to arrays 2021-06-28 11:05:52 +01:00
Jeroen van Rijn 8e5c3141f6 Merge pull request #1047 from Kelimion/zlib_optimize
ZLIB: Fix edge case where initial buffer < 258 bytes.
2021-06-27 18:49:09 +02:00
Jeroen van Rijn 87aaa9c3f0 ZLIB: Fix edge case where initial buffer < 258 bytes. 2021-06-27 18:44:36 +02:00
Jeroen van Rijn 095605b7db Merge pull request #1046 from Kelimion/zlib_optimize
ZLIB: Optimize
2021-06-27 16:54:15 +02:00
Jeroen van Rijn 6836b501af Merge branch 'master' into zlib_optimize 2021-06-27 16:50:27 +02:00
Jeroen van Rijn d949d5a046 ZLIB: cleanup. 2021-06-27 16:48:12 +02:00
Jeroen van Rijn 064516bf0b PNG: Inform inflate about expected output size for extra speed. 2021-06-27 13:57:12 +02:00
Jeroen van Rijn eaf88bcc4d PNG: Let PNG use the new compress I/O routines. 2021-06-27 13:51:52 +02:00
gingerBill 76d3bab955 Modify scope finding rules for distinct types in lb_debug_type 2021-06-27 12:21:11 +01:00
Jeroen van Rijn 02f9668185 ZLIB: Split up input from stream and memory into own code paths. 2021-06-27 13:19:24 +02:00
gingerBill abda75feee Add bufio.Lookahead_Reader 2021-06-26 23:45:45 +01:00
gingerBill a779cb2798 Fix #1044 2021-06-26 23:31:04 +01:00
gingerBill 5e42675b42 Allow alternative syntax for offset_of: offset_of(Type, field), offset_of(value.field) 2021-06-26 23:19:46 +01:00
gingerBill 11c565e199 Fix semicolon insertion rule for --- 2021-06-26 22:47:12 +01:00
Jeroen van Rijn 4689a6b341 Refactor compress.Context struct. 2021-06-26 22:25:55 +02:00
Jeroen van Rijn 30a5808460 ZLIB: Moar faster. 2021-06-26 20:40:39 +02:00
Jeroen van Rijn 8ba1c9a6cd ZLIB: Remove superfluous code. 2021-06-26 17:44:12 +02:00
Jeroen van Rijn 65b78b1aa9 So far, so good. 2021-06-26 15:11:15 +02:00
Jeroen van Rijn c369719362 Merge branch 'master' into zlib_optimize 2021-06-26 13:40:22 +02:00
Jeroen van Rijn 40a12cca53 ZLIB: If output size is known, reserve that much. 2021-06-26 13:17:14 +02:00
gingerBill d8940f5fd7 Support compound literals for struct #raw_union types 2021-06-26 12:08:14 +01:00
gingerBill 74dee82dbf Fix compiler errors 2021-06-25 14:33:42 +01:00
gingerBill f1cf724bd4 Add bufio.Scanner 2021-06-25 14:31:35 +01:00
gingerBill fc809d3fad Merge branch 'master' of https://github.com/odin-lang/Odin 2021-06-24 19:41:36 +01:00
gingerBill 42d135aade Change logic for comparison against nil for array-like data types (compare the pointer rather than the length/capacity) 2021-06-24 19:39:51 +01:00
Jeroen van Rijn ab12ca69af Merge pull request #1040 from Kelimion/zlib_optimize
Adler32 speedup.
2021-06-24 19:15:22 +02:00
Jeroen van Rijn 17748f18b9 Adler32 speedup. 2021-06-24 19:06:39 +02:00
gingerBill 3803bdff5f Allow bufio.Reader and bufio.Writer to have a configurable max_consecutive_empty_(reads|writes) field 2021-06-24 15:56:58 +01:00
gingerBill 0a94a67190 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-06-24 15:55:50 +01:00
gingerBill 8dcb14fbc2 Add helper procedures for strings.Reader creation 2021-06-24 15:55:42 +01:00
Jeroen van Rijn f62f40e508 Merge pull request #1039 from Kelimion/zlib_optimize
ZLIB: Another 10%+ faster.
2021-06-24 15:02:02 +02:00
Jeroen van Rijn 980aa37bee ZLIB: Another 10%+ faster. 2021-06-24 14:56:28 +02:00
gingerBill 1e9cc058a0 Update hash.crc32 to use slicing-by-8 algorithm to improve throughput by ~3.5x 2021-06-24 00:03:59 +01:00
Jeroen van Rijn 824efc82b9 Merge pull request #1036 from Kelimion/zlib_optimize
ZLIB: More faster.
2021-06-23 22:25:02 +02:00
Jeroen van Rijn 1cfe226686 ZLIB: More faster. 2021-06-23 22:18:17 +02:00
Jeroen van Rijn ea0ce7bd2c Merge pull request #1035 from Kelimion/zlib_optimize
Zlib optimize
2021-06-23 20:15:32 +02:00
Jeroen van Rijn 342adb627d All reads now skip stream if in memory. 2021-06-23 16:32:48 +02:00
Jeroen van Rijn a70635d2f6 Most reads now go through buffer for zlib. 2021-06-23 16:32:48 +02:00
Jeroen van Rijn 5cb16c4cd1 All reads now go through read_slice. 2021-06-23 16:32:48 +02:00
Jeroen van Rijn 538004ba5f Introduce read_slice, make read_u8 use it. 2021-06-23 16:32:48 +02:00
Jeroen van Rijn 8663c64e47 Refactor ZLIB structs. 2021-06-23 16:32:47 +02:00
gingerBill bb3ffdbdfb Merge branch 'master' of https://github.com/odin-lang/Odin 2021-06-23 14:55:53 +01:00
gingerBill fcf7cf973b Add documentation for -verbose-errors 2021-06-23 14:55:40 +01:00
Jeroen van Rijn fb2e1c32bd Merge pull request #1034 from Kelimion/bytes_util
Move `bytes` utils back to EXR code for the time being.
2021-06-22 16:48:07 +02:00
Jeroen van Rijn ae0b8fce44 Move bytes utils back to EXR code for the time being.
Also, allow PNG example to be run directly from `core:image/png` directory.
2021-06-22 16:39:00 +02:00
Jeroen van Rijn d2e55f9ffa Merge pull request #1032 from Kelimion/png_fix
PNG: Fix leak if you don't ask for metadata.
2021-06-21 22:56:39 +02:00
Jeroen van Rijn d5e2b387fa PNG: Fix leak if you don't ask for metadata. 2021-06-21 22:47:54 +02:00
Jeroen van Rijn 922b511a24 Merge pull request #1031 from Kelimion/zlib_fix
ZLIB: fix.
2021-06-21 22:16:56 +02:00
Jeroen van Rijn 9de9111082 ZLIB: fix. 2021-06-21 22:15:04 +02:00
Jeroen van Rijn 5a7fe2e3d9 Merge pull request #1030 from Kelimion/zlib_optimize
Comment out tracy imports.
2021-06-21 21:43:57 +02:00
Jeroen van Rijn 1e8c12c2a3 Comment out tracy imports. 2021-06-21 21:41:56 +02:00
Jeroen van Rijn b92c70e55c Merge pull request #1029 from Kelimion/zlib_optimize
ZLIB: Start optimization.
2021-06-21 21:26:52 +02:00
Jeroen van Rijn 352494cbb4 ZLIB: Start optimization. 2021-06-21 21:05:52 +02:00
Jeroen van Rijn 797c41950a Merge pull request #1027 from Kelimion/png
Replace `core:image`'s `sidecar` with explicit pointer and type
2021-06-21 16:41:38 +02:00
Jeroen van Rijn e036a321a0 Replace core:image's sidecar with explicit metadata_ptr and metadata_type.
To unpack, use:
```odin

v: ^png.Info;

if img.metadata_ptr != nil && img.metadata_type == png.Info {
	v = (^png.Info)(img.metadata_ptr);
	...
}
```
2021-06-21 16:32:42 +02:00
Jeroen van Rijn 18471f358e Merge pull request #1025 from Kelimion/png_info
Change PNG's img.sidecar to ^Info, make img.depth an int.
2021-06-20 18:40:46 +02:00
Jeroen van Rijn 55d09251d8 Change PNG's img.sidecar to ^Info, make img.depth an int.
For compatibility with the upcoming OpenEXR code, img.depth is now an int.
Like OpenEXR's code, it will now also return metadata as ^Info instead of Info.

The example was updated to retrieve the metadata this way.

It regrettably does not fix: #1018. That seems to be a codegen issue in the test runner or elsewhere.
2021-06-20 18:27:23 +02:00
Jeroen van Rijn d66fd71d21 Merge pull request #1024 from Kelimion/defer_fix
GZIP defer diverging fix in gzip example.
2021-06-20 17:40:15 +02:00
Jeroen van Rijn f10fc2a494 Merge pull request #1023 from Kelimion/test_runner_fix
Fix Windows test runner.
2021-06-20 17:37:04 +02:00
Jeroen van Rijn 055d8c5370 Fix Windows test runner. 2021-06-20 17:33:39 +02:00
Jeroen van Rijn 955472bd21 GZIP defer diverging fix in gzip example. 2021-06-20 17:21:18 +02:00
gingerBill a2d5f660ed Merge pull request #1022 from Kelimion/buffer_convert
Add `bytes.buffer_create_of_type` and `bytes.buffer_convert_to_type`.
2021-06-18 16:41:48 +01:00
Jeroen van Rijn 8a4b9ddaa3 Fix comment. 2021-06-18 15:42:04 +02:00
Jeroen van Rijn 54a2b6f00e Add bytes.buffer_create_of_type and bytes.buffer_convert_to_type.
Convenience functions to reinterpret or cast one buffer to another type, or create a buffer of a specific type.

	Example:
```odin
	fmt.println("Convert []f16le (x2) to []f32 (x2).");
	b := []u8{0, 60, 0, 60}; // == []f16{1.0, 1.0}

	res, backing, had_to_allocate, err := bytes.buffer_convert_to_type(2, f32, f16le, b);
	fmt.printf("res      : %v\n", res);              // [1.000, 1.000]
	fmt.printf("backing  : %v\n", backing);          // &Buffer{buf = [0, 0, 128, 63, 0, 0, 128, 63], off = 0, last_read = Invalid}
	fmt.printf("allocated: %v\n", had_to_allocate);  // true
	fmt.printf("err      : %v\n", err);              // false

	if had_to_allocate { defer bytes.buffer_destroy(backing); }

	fmt.println("\nConvert []f16le (x2) to []u16 (x2).");

	res2: []u16;
	res2, backing, had_to_allocate, err = bytes.buffer_convert_to_type(2, u16, f16le, b);
	fmt.printf("res      : %v\n", res2);             // [15360, 15360]
	fmt.printf("backing  : %v\n", backing);          // Buffer.buf points to `b` because it could be converted in-place.
	fmt.printf("allocated: %v\n", had_to_allocate);  // false
	fmt.printf("err      : %v\n", err);              // false

	if had_to_allocate { defer bytes.buffer_destroy(backing); }

	fmt.println("\nConvert []f16le (x2) to []u16 (x2), force_convert=true.");

	res2, backing, had_to_allocate, err = bytes.buffer_convert_to_type(2, u16, f16le, b, true);
	fmt.printf("res      : %v\n", res2);             // [1, 1]
	fmt.printf("backing  : %v\n", backing);          // Buffer.buf points to `b` because it could be converted in-place.
	fmt.printf("allocated: %v\n", had_to_allocate);  // false
	fmt.printf("err      : %v\n", err);              // false

	if had_to_allocate { defer bytes.buffer_destroy(backing); }
```
2021-06-18 15:25:36 +02:00
gingerBill abe728dbbb Add intrinsics.type_is_endian_platform 2021-06-17 20:39:00 +01:00
gingerBill 574ceb37a9 Correct selector call expression chaining behaviour (a bit of a hack) 2021-06-16 17:04:05 +01:00
gingerBill dbdc4471c2 Fix double evaluation bug with selector call expressions x->y(z) 2021-06-16 14:03:12 +01:00
gingerBill af95381bf8 Add missing -> ! annotation 2021-06-16 12:12:24 +01:00
gingerBill 41f2539484 Improve logic for diverging procedures by checking if it terminates 2021-06-16 12:07:24 +01:00
gingerBill 8f57bb0799 Add unreachable detection for deferred statements in a scope which contains a diverging procedure call
```odin
{
    defer foo(); // Unreachable defer statement due to diverging procedure call at the end of the current scope
    os.exit(0);
}
```
2021-06-16 11:41:29 +01:00
gingerBill 84a4188c72 Fix #1017 2021-06-15 01:16:19 +01:00
gingerBill 31f1e0aeae Fix #1019 2021-06-15 01:13:16 +01:00
gingerBill 4b8cbb5a3b Fix #1015 2021-06-14 13:26:28 +01:00
gingerBill 3e7aabe6d8 Change uses for parapoly records to use $ always 2021-06-14 11:43:35 +01:00
gingerBill d4df325e0a Just create context when required 2021-06-14 11:41:50 +01:00
gingerBill 9f8a63cb43 More minor stylization changes (remove unneeded parentheses) 2021-06-14 11:34:31 +01:00
gingerBill 6f745677b4 Minor formatting changes 2021-06-14 11:30:00 +01:00
gingerBill 86649e6b44 Core library clean up: Make range expressions more consistent and replace uses of .. with ..= 2021-06-14 11:15:25 +01:00
gingerBill 3ca887a60a Add struct_fields_zipped and enum_fields_zipped (allowing for iteration through an #soa slice) 2021-06-14 11:04:51 +01:00
gingerBill 312a1e8a94 Fix context logic 2021-06-13 16:00:20 +01:00
gingerBill 9a311ab9e7 Remove dead code 2021-06-12 16:47:20 +01:00
gingerBill 7d92eaaeb2 Correct context logic in lb_build_addr 2021-06-12 16:45:44 +01:00
gingerBill 582f423b67 Improve vector arithmetic generation for array programming operations 2021-06-12 16:37:20 +01:00
gingerBill c2524464f9 Fix remove_temp_files 2021-06-12 16:23:41 +01:00
gingerBill 55e472cdb6 Fix linkage problem for procedures required by LLVM 2021-06-10 12:23:08 +01:00
gingerBill e6ad773a88 Minor code clean up 2021-06-09 23:47:44 +01:00
gingerBill 82eae32bca Improve code generation for type switch statements to use a jump table by default 2021-06-09 23:46:00 +01:00
gingerBill b0e21bd616 Allow trivial optimizations for switch statements of typeid 2021-06-09 23:05:37 +01:00
gingerBill 7b88bed098 Do trivial SwitchInstr optimization for constant case switch statements 2021-06-09 22:55:08 +01:00
gingerBill 28abf5d33b Correct minimum dependency for complex32 2021-06-08 21:20:33 +01:00
gingerBill fb8ad338d0 Keep -vet happy 2021-06-08 18:26:38 +01:00
gingerBill ee60be0137 Improve code generation hints for return statements which return by pointer 2021-06-08 17:17:53 +01:00
gingerBill 9efd4c5097 Aid code generation on non-release builds 2021-06-08 17:17:24 +01:00
gingerBill f30e6f50bd Reorganize code to improve code generation 2021-06-08 16:21:19 +01:00
gingerBill 8ec2ca9dcd Remove context.thread_id 2021-06-08 15:57:00 +01:00
gingerBill f19bb0f4d4 Make default calling convention code more correct to read 2021-06-08 14:33:49 +01:00
gingerBill 76bb82a726 Minor alignment cleanup for swizzle load 2021-06-08 14:27:36 +01:00
gingerBill 8e62f9c83c Correct is_operand_value for Swizzle addressing modes 2021-06-08 14:23:44 +01:00
gingerBill 696f758435 Fix and improve swizzle loads for ordered indices 2021-06-08 14:19:27 +01:00
gingerBill 6421152104 Fix show-timings header for -lld on windows 2021-06-08 13:19:19 +01:00
gingerBill 1e989f5c10 Fix -lld on Windows 2021-06-08 13:10:22 +01:00
gingerBill 3eb42ecb55 Minor improvements to -use-separate-modules 2021-06-08 13:00:20 +01:00
gingerBill 286cb60c45 Minor changes to tools/odinfmt 2021-06-08 12:18:55 +01:00
gingerBill 28e9a4f79c Replace js_wasm32 with freestanding_wasm32 2021-06-08 12:18:26 +01:00
gingerBill e79fb68291 Correct #soa type creation 2021-06-08 11:23:23 +01:00
gingerBill 16eaa17ed9 Fix -target:js_wasm32 for core:runtime 2021-06-08 11:20:39 +01:00
gingerBill 9491c13a5c Fix #1011 by unifying the logic 2021-06-08 11:09:41 +01:00
gingerBill 8d8adac1b4 Fix lb_build_defer_stmt 2021-06-08 10:43:11 +01:00
gingerBill ba6c63e366 Fix full_path_from_name allocator behaviour 2021-06-08 10:14:35 +01:00
gingerBill 963b1a12d7 Correct code for #simd in unions 2021-06-06 16:56:03 +01:00
gingerBill 89890d7900 Correct union tag size for large alignments 2021-06-06 16:34:51 +01:00
gingerBill 661fcad895 Add examples/all which imports every package
This is useful for knowing what exists and producing documentation with `odin doc`
2021-06-06 13:05:54 +01:00
gingerBill cef16feb0b Fix #861 - Add extra check on missing main 2021-06-06 12:46:59 +01:00
gingerBill 84b851f578 Add warning to variables which may overflow the stack on declaration; #Fix 661 2021-06-06 12:42:39 +01:00
gingerBill 785c27daa7 Fix 128-bit integer to float cast by explicitly calling the procedure direct; Fix #781 2021-06-06 12:35:38 +01:00
gingerBill 795a5910cf Add support for Addressing_OptionalOkPtr
Allowing for `i, ok := &x.(T);` (type assertions) and `v, ok := &m[k];` (map indexing)
2021-06-06 12:18:45 +01:00
gingerBill 4c21f9495d Clean up lbAddr_Swizzle logic for load and store 2021-06-05 23:56:59 +01:00
gingerBill f119fd1ee1 Use shufflevector when possible for lbAddr_Swizzle load 2021-06-05 22:50:23 +01:00
gingerBill 46ab822316 Improved lb_build_assign_stmt_array logic 2021-06-05 22:07:39 +01:00
gingerBill 104aea9f42 Improve error message for addressing a swizzle intermediate array value 2021-06-05 18:25:51 +01:00
gingerBill a2f2041aa6 Fix lb_build_assign_stmt_array for lbAddr_Swizzle 2021-06-05 17:33:42 +01:00
gingerBill 599d18f26f Experimental support for inline swizzling for array types of len <= 4 e.g. v.xyz, v.argb, v.xxx 2021-06-05 17:22:39 +01:00
gingerBill 61084d832d Add missing doc_format flags for entities and improve docs for the odin package 2021-06-05 15:55:19 +01:00
gingerBill b957996577 Add extra documentation to doc_format.odin 2021-06-05 15:26:05 +01:00
gingerBill f41150f8e9 Fix transposing 2021-06-04 15:10:53 +01:00
gingerBill 21adad4e09 Fix typo 2021-06-04 15:09:55 +01:00
gingerBill 47f9e8f850 Fix ast_end_token for [?]T types 2021-06-03 11:35:27 +01:00
gingerBill ba3f2a6a0c All spaces in import-like paths 2021-06-03 10:28:45 +01:00
gingerBill b9888f8f68 Fix linalg.transpose 2021-06-03 10:05:05 +01:00
gingerBill 32cda5d56a Or did it?! 2021-06-02 22:12:38 +01:00
gingerBill a4d9847f45 FINALLY fix lazy_buffer_destroy 2021-06-02 22:12:20 +01:00
gingerBill 8aa6d70dec Fix filepath.lazy_buffer 2021-06-02 12:21:20 +01:00
gingerBill ea6b222430 Clean up filepath.lazy_buffer memory leak 2021-06-02 12:19:25 +01:00
gingerBill 91b4bf3daa Minor clean up 2021-06-02 10:39:47 +01:00
1012 changed files with 347534 additions and 67446 deletions
+1
View File
@@ -1,3 +1,4 @@
# These are supported funding model platforms
github: odin-lang
patreon: gingerbill
+2 -2
View File
@@ -11,8 +11,8 @@ assignees: ''
Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
* Operating System:
* Please paste `odin version` output:
* Operating System & Odin Version:
* Please paste `odin report` output:
## Expected Behavior
+144 -25
View File
@@ -6,36 +6,105 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Download LLVM
run: sudo apt-get install llvm-11 clang-11 llvm
- name: Download LLVM, botan
run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan
- name: build odin
run: make release
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Odin check
run: ./odin check examples/demo/demo.odin -vet
run: ./build_odin.sh release
- name: Odin version
run: ./odin version
timeout-minutes: 1
- name: Odin report
run: ./odin report
timeout-minutes: 1
- name: Odin check
run: ./odin check examples/demo -vet
timeout-minutes: 10
- name: Odin run
run: ./odin run examples/demo
timeout-minutes: 10
- name: Odin run -debug
run: ./odin run examples/demo -debug
timeout-minutes: 10
- name: Odin check examples/all
run: ./odin check examples/all -strict-style
timeout-minutes: 10
- name: Core library tests
run: |
cd tests/core
make
timeout-minutes: 10
- name: Vendor library tests
run: |
cd tests/vendor
make
timeout-minutes: 10
- name: Odin issues tests
run: |
cd tests/issues
./run.sh
timeout-minutes: 10
- name: Odin check examples/all for Linux i386
run: ./odin check examples/all -vet -strict-style -target:linux_i386
timeout-minutes: 10
- name: Odin check examples/all for FreeBSD amd64
run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64
timeout-minutes: 10
- name: Odin check examples/all for OpenBSD amd64
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
timeout-minutes: 10
build_macOS:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Download LLVM and setup PATH
- name: Download LLVM, botan and setup PATH
run: |
brew install llvm@11
brew install llvm@11 botan
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
- name: build odin
run: make release
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Odin check
run: ./odin check examples/demo/demo.odin -vet
run: ./build_odin.sh release
- name: Odin version
run: ./odin version
timeout-minutes: 1
- name: Odin report
run: ./odin report
timeout-minutes: 1
- name: Odin check
run: ./odin check examples/demo -vet
timeout-minutes: 10
- name: Odin run
run: ./odin run examples/demo
timeout-minutes: 10
- name: Odin run -debug
run: ./odin run examples/demo -debug
timeout-minutes: 10
- name: Odin check examples/all
run: ./odin check examples/all -strict-style
timeout-minutes: 10
- name: Core library tests
run: |
cd tests/core
make
timeout-minutes: 10
- name: Vendor library tests
run: |
cd tests/vendor
make
timeout-minutes: 10
- name: Odin issues tests
run: |
cd tests/issues
./run.sh
timeout-minutes: 10
- name: Odin check examples/all for Darwin arm64
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
timeout-minutes: 10
- name: Odin check examples/all for Linux arm64
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
timeout-minutes: 10
build_windows:
runs-on: windows-latest
runs-on: windows-2019
steps:
- uses: actions/checkout@v1
- name: build Odin
@@ -43,17 +112,67 @@ jobs:
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
./build.bat 1
- name: Odin run
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo/demo.odin
- name: Odin version
run: ./odin version
timeout-minutes: 1
- name: Odin report
run: ./odin report
timeout-minutes: 1
- name: Odin check
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/demo/demo.odin -vet
- name: Odin version
run: ./odin version
odin check examples/demo -vet
timeout-minutes: 10
- name: Odin run
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo
timeout-minutes: 10
- name: Odin run -debug
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo -debug
timeout-minutes: 10
- name: Odin check examples/all
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style
timeout-minutes: 10
- name: Core library tests
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\core
call build.bat
timeout-minutes: 10
- name: Vendor library tests
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\vendor
call build.bat
timeout-minutes: 10
- name: core:math/big tests
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\core\math\big
call build.bat
timeout-minutes: 10
- name: Odin issues tests
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\issues
call run.bat
timeout-minutes: 10
- name: Odin check examples/all for Windows 32bits
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style -target:windows_i386
timeout-minutes: 10
+16 -6
View File
@@ -7,7 +7,7 @@ on:
jobs:
build_windows:
runs-on: windows-latest
runs-on: windows-2019
steps:
- uses: actions/checkout@v1
- name: build Odin
@@ -19,7 +19,7 @@ jobs:
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo/demo.odin
odin run examples/demo
- name: Copy artifacts
run: |
rm bin/llvm/windows/LLVM-C.lib
@@ -28,6 +28,7 @@ jobs:
cp LLVM-C.dll dist
cp -r shared dist
cp -r core dist
cp -r vendor dist
cp -r bin dist
cp -r examples dist
- name: Upload artifact
@@ -40,17 +41,18 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: (Linux) Download LLVM
run: sudo apt-get install llvm-11 clang-11 llvm
run: sudo apt-get install llvm-11 clang-11
- name: build odin
run: make nightly
- name: Odin run
run: ./odin run examples/demo/demo.odin
run: ./odin run examples/demo
- name: Copy artifacts
run: |
mkdir dist
cp odin dist
cp -r shared dist
cp -r core dist
cp -r vendor dist
cp -r examples dist
- name: Upload artifact
uses: actions/upload-artifact@v1
@@ -70,13 +72,14 @@ jobs:
- name: build odin
run: make nightly
- name: Odin run
run: ./odin run examples/demo/demo.odin
run: ./odin run examples/demo
- name: Copy artifacts
run: |
mkdir dist
cp odin dist
cp -r shared dist
cp -r core dist
cp -r vendor dist
cp -r examples dist
- name: Upload artifact
uses: actions/upload-artifact@v1
@@ -90,7 +93,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-python@v2
with:
python-version: '3.x'
python-version: '3.8.x'
- name: Install B2 CLI
shell: bash
@@ -124,16 +127,23 @@ jobs:
BUCKET: ${{ secrets.B2_BUCKET }}
DAYS_TO_KEEP: ${{ secrets.B2_DAYS_TO_KEEP }}
run: |
echo Authorizing B2 account
b2 authorize-account "$APPID" "$APPKEY"
echo Uploading artifcates to B2
chmod +x ./ci/upload_create_nightly.sh
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
./ci/upload_create_nightly.sh "$BUCKET" ubuntu-amd64 ubuntu_artifacts/
./ci/upload_create_nightly.sh "$BUCKET" macos-amd64 macos_artifacts/
echo Deleting old artifacts in B2
python3 ci/delete_old_binaries.py "$BUCKET" "$DAYS_TO_KEEP"
echo Creating nightly.json
python3 ci/create_nightly_json.py "$BUCKET" > nightly.json
echo Uploading nightly.json
b2 upload-file "$BUCKET" nightly.json nightly.json
echo Clear B2 account info
b2 clear-account
+5
View File
@@ -7,6 +7,9 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# For macOS
.DS_Store
# Build results
[Dd]ebug/
[Dd]ebugPublic/
@@ -276,3 +279,5 @@ shared/
*.ll
*.sublime-workspace
examples/bug/
build.sh
+10 -6
View File
@@ -1,14 +1,18 @@
Copyright (c) 2016-2021 Ginger Bill. All rights reserved.
Copyright (c) 2016-2022 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
BIN
View File
Binary file not shown.
+11 -45
View File
@@ -1,53 +1,19 @@
GIT_SHA=$(shell git rev-parse --short HEAD)
DISABLED_WARNINGS=-Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined
LDFLAGS=-pthread -ldl -lm -lstdc++
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
CC=clang
OS=$(shell uname)
ifeq ($(OS), Darwin)
LLVM_CONFIG=llvm-config
ifneq ($(shell llvm-config --version | grep '^11\.'),)
LLVM_CONFIG=llvm-config
else
$(error "Requirement: llvm-config must be version 11")
endif
LDFLAGS:=$(LDFLAGS) -liconv
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) -lLLVM-C
endif
ifeq ($(OS), Linux)
LLVM_CONFIG=llvm-config-11
ifneq ($(shell which llvm-config-11 2>/dev/null),)
LLVM_CONFIG=llvm-config-11
else
ifneq ($(shell llvm-config --version | grep '^11\.'),)
LLVM_CONFIG=llvm-config
else
$(error "Requirement: llvm-config must be version 11")
endif
endif
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
endif
all: debug demo
all: debug
demo:
./odin run examples/demo/demo.odin
./odin run examples/demo/demo.odin -file
report:
./odin report
debug:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
./build_odin.sh debug
release:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
./build_odin.sh release
release_native:
./build_odin.sh release-native
nightly:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
./build_odin.sh nightly
+22 -98
View File
@@ -1,7 +1,7 @@
<p align="center">
<img src="misc/logo-slim.png" alt="Odin logo" height="120">
<img src="misc/logo-slim.png" alt="Odin logo" style="width:65%">
<br/>
A fast, concise, readable, pragmatic and open sourced programming language.
The Data-Oriented Language for Sane Software Development.
<br/>
<br/>
<a href="https://github.com/odin-lang/odin/releases/latest">
@@ -11,7 +11,7 @@
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
</a>
<br>
<a href="https://discord.gg/hnwN2Rj">
<a href="https://discord.gg/odinlang">
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
</a>
<a href="https://github.com/odin-lang/odin/actions">
@@ -21,11 +21,8 @@
# The Odin Programming Language
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of creating an alternative to C with the following goals:
* simplicity
* high performance
* built for modern systems
* joy of programming
Odin is a general-purpose programming language with distinct typing, built for high performance, modern systems, and built-in data-oriented data types. The Odin Programming Language, the C alternative for the joy of programming.
Website: [https://odin-lang.org/](https://odin-lang.org/)
@@ -35,33 +32,36 @@ package main
import "core:fmt"
main :: proc() {
program := "+ + * 😃 - /";
accumulator := 0;
program := "+ + * 😃 - /"
accumulator := 0
for token in program {
switch token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case '😃': accumulator *= accumulator;
case '+': accumulator += 1
case '-': accumulator -= 1
case '*': accumulator *= 2
case '/': accumulator /= 2
case '😃': accumulator *= accumulator
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
program, accumulator)
}
```
## Documentation
#### [Getting Started](https://odin-lang.org/docs/install)
Instructions for downloading and installing the Odin compiler and libraries.
#### [Nightly Builds](https://odin-lang.org/docs/nightly/)
Get the latest nightly builds of Odin.
### Learning Odin
#### [Overview of Odin](https://odin-lang.org/docs/overview)
@@ -72,6 +72,10 @@ An overview of the Odin programming language.
Answers to common questions about Odin.
#### [Packages](https://pkg.odin-lang.org/)
Documentation for all the official packages part of the [core](https://pkg.odin-lang.org/core/) and [vendor](https://pkg.odin-lang.org/vendor/) library collections.
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
A wiki maintained by the Odin community.
@@ -80,92 +84,12 @@ A wiki maintained by the Odin community.
Get live support and talk with other odiners on the Odin Discord.
### References
#### [Language Specification](https://odin-lang.org/ref/spec)
The official Odin Language specification.
### Articles
#### [The Odin Blog](https://odin-lang.org/blog)
#### [The Odin Blog](https://odin-lang.org/news/)
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
## Setup
Odin only supports x86-64/amd64 at the moment (64-bit), relies on LLVM for code generation and an external linker.
In addition, the following platform-specific steps are necessary:
- Windows
* Have Visual Studio installed (MSVC 2010 or later, for the linker)
* Open a valid command prompt:
* **Basic:** run the `x64 Native Tools Command Prompt for VS2017` shortcut bundled with VS 2017, or
* **Advanced:** run `vcvarsall.bat x64` from a blank `cmd` session
- MacOS
* Have LLVM explicitly installed (`brew install llvm`)
* Have XCode installed (version X.X or later, for linking)
* Make sure the LLVM binaries and the linker are added to your `$PATH` environmental variable
- GNU/Linux
* Have LLVM installed (opt/llc)
* Have Clang installed (version X.X or later, for linking)
* Make sure the LLVM binaries and the linker are added to your `$PATH` environmental variable
Then build the compiler by calling `build.bat` (Windows) or `make` (Linux/MacOS). This will automatically run the demo program if successful.
**Notes for Linux:**: The compiler currently relies on the `core` and `shared` library collection being relative to the compiler executable. Installing the compiler in the usual sense (to `/usr/local/bin` or similar) is therefore not as straight forward as you need to make sure the mentioned libraries are available. As a result, it is recommended to simply explicitly invoke the compiler with `/path/to/odin` in your preferred build system, or add `/path/to/odin` to `$PATH`.
Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#getting-started-with-odin) for more information.
## Requirements to build and run
Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#getting-started-with-odin).
- Windows
* x86-64/amd64
* MSVC 2010 installed (C++11 support)
* Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path
- MacOS
* x86-64/amd64
* LLVM explicitly installed (`brew install llvm`)
* XCode installed (for the linker)
- GNU/Linux
* x86-64/amd64
* Build tools (ld)
* LLVM installed
* Clang installed (temporary - this is Calling the linker for now)
- FreeBSD
* x86-64/amd64
* Build tools (ld)
* LLVM installed
* Clang installed (temporary - this is Calling the linker for now)
Other platforms may be supported but are experimental for the time being.
## Warnings
* The Odin compiler is still in development.
## Demonstrations:
* First Talk & Demo
- [Talk](https://youtu.be/TMCkT-uASaE?t=338)
- [Demo](https://youtu.be/TMCkT-uASaE?t=1800)
- [Q&A](https://youtu.be/TMCkT-uASaE?t=5749)
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
* [Default and Named Arguments; Explicit Parametric Polymorphism](https://www.youtube.com/watch?v=-XQZE6S6zUU)
* [Loadsachanges](https://www.youtube.com/watch?v=ar0vFMoMtrI)
* [Packages, Bit Sets, cstring](https://youtu.be/b8bJbjiXZrQ)
- [Q&A](https://youtu.be/5jmxyIfyyTk)
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
NASM is now licensed under the 2-clause BSD license, also known as the
simplified BSD license.
Copyright 1996-2010 the NASM Authors - All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Binary file not shown.
Binary file not shown.
+14 -12
View File
@@ -3,7 +3,7 @@
setlocal EnableDelayedExpansion
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
)
set curr_year=%CURR_DATE_TIME:~0,4%
@@ -23,9 +23,9 @@ if "%1" == "1" (
:: Normal = 0, CI Nightly = 1
if "%2" == "1" (
set nightly=1
set nightly=1
) else (
set nightly=0
set nightly=0
)
set odin_version_raw="dev-%curr_year%-%curr_month%"
@@ -46,12 +46,11 @@ if %release_mode% EQU 0 ( rem Debug
set compiler_warnings= ^
-W4 -WX ^
-wd4100 -wd4101 -wd4127 -wd4189 ^
-wd4201 -wd4204 ^
-wd4456 -wd4457 -wd4480 ^
-wd4512
-wd4100 -wd4101 -wd4127 -wd4146 ^
-wd4456 -wd4457
set compiler_includes=
set compiler_includes= ^
/Isrc\
set libs= ^
kernel32.lib ^
bin\llvm\windows\LLVM-C.lib
@@ -70,11 +69,14 @@ set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.cpp" /link %linker_settings% -OUT:%exe_name%
cl %compiler_settings% "src\main.cpp" "src\libtommath.cpp" /link %linker_settings% -OUT:%exe_name%
if %errorlevel% neq 0 goto end_of_build
if %release_mode% EQU 0 odin run examples/demo/demo.odin
call build_vendor.bat
if %errorlevel% neq 0 goto end_of_build
if %release_mode% EQU 0 odin run examples/demo
del *.obj > NUL 2> NUL
:end_of_build
:end_of_build
Executable
+150
View File
@@ -0,0 +1,150 @@
#!/bin/bash
set -eu
GIT_SHA=$(git rev-parse --short HEAD)
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
LDFLAGS="-pthread -lm -lstdc++"
CFLAGS="-std=c++14 -DGIT_SHA=\"$GIT_SHA\""
CFLAGS="$CFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
CC=clang
OS=$(uname)
panic() {
printf "%s\n" "$1"
exit 1
}
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
config_darwin() {
ARCH=$(uname -m)
LLVM_CONFIG=llvm-config
# allow for arm only llvm's with version 13
if [ ARCH == arm64 ]; then
MIN_LLVM_VERSION=("13.0.0")
else
# allow for x86 / amd64 all llvm versions begining from 11
MIN_LLVM_VERSION=("11.1.0")
fi
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
if [ ARCH == arm64 ]; then
panic "Requirement: llvm-config must be base version 13 for arm64"
else
panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86"
fi
fi
LDFLAGS="$LDFLAGS -liconv -ldl"
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -lLLVM-C"
}
config_freebsd() {
LLVM_CONFIG=/usr/local/bin/llvm-config11
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
}
config_openbsd() {
LLVM_CONFIG=/usr/local/bin/llvm-config
LDFLAGS="$LDFLAGS -liconv"
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
}
config_linux() {
if which llvm-config > /dev/null 2>&1; then
LLVM_CONFIG=llvm-config
elif which llvm-config-11 > /dev/null 2>&1; then
LLVM_CONFIG=llvm-config-11
elif which llvm-config-11-64 > /dev/null 2>&1; then
LLVM_CONFIG=llvm-config-11-64
else
panic "Unable to find LLVM-config"
fi
MIN_LLVM_VERSION=("11.0.0")
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
panic "Requirement: llvm-config must be base version greater than 11"
fi
LDFLAGS="$LDFLAGS -ldl"
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
}
build_odin() {
case $1 in
debug)
EXTRAFLAGS="-g"
;;
release)
EXTRAFLAGS="-O3"
;;
release-native)
EXTRAFLAGS="-O3 -march=native"
;;
nightly)
EXTRAFLAGS="-DNIGHTLY -O3"
;;
*)
panic "Build mode unsupported!"
esac
set -x
$CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin
set +x
}
run_demo() {
./odin run examples/demo/demo.odin -file
}
case $OS in
Linux)
config_linux
;;
Darwin)
config_darwin
;;
OpenBSD)
config_openbsd
;;
FreeBSD)
config_freebsd
;;
*)
panic "Platform unsupported!"
esac
if [[ $# -eq 0 ]]; then
build_odin debug
run_demo
exit 0
fi
if [[ $# -eq 1 ]]; then
case $1 in
report)
if [[ ! -f "./odin" ]]; then
build_odin debug
fi
./odin report
exit 0
;;
*)
build_odin $1
;;
esac
run_demo
exit 0
else
panic "Too many arguments!"
fi
+17
View File
@@ -0,0 +1,17 @@
@echo off
setlocal EnableDelayedExpansion
rem build the .lib files already exist
if not exist "vendor\stb\lib\*.lib" (
pushd vendor\stb\src
call build.bat
popd
)
if not exist "vendor\miniaudio\lib\*.lib" (
pushd vendor\miniaudio\src
call build.bat
popd
)
+1 -1
View File
@@ -18,7 +18,7 @@ def main():
name = remove_prefix(data['fileName'], "nightly/")
url = f"https://f001.backblazeb2.com/file/{bucket}/nightly/{urllib.parse.quote_plus(name)}"
sha1 = data['contentSha1']
size = int(data['contentLength'])
size = int(data['size'])
ts = int(data['fileInfo']['src_last_modified_millis'])
date = datetime.datetime.fromtimestamp(ts/1000).strftime('%Y-%m-%d')
+83
View File
@@ -0,0 +1,83 @@
package bufio
import "core:io"
// Loadahead_Reader provides io lookahead.
// This is useful for tokenizers/parsers.
// Loadahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Loadahead_Reader's buffer size
// will EXACTLY match the specified size, whereas bufio.Reader's buffer size may differ from the specified size.
// This makes sure that the buffer will not be accidentally read beyond the expected size.
Loadahead_Reader :: struct {
r: io.Reader,
buf: []byte,
n: int,
}
lookahead_reader_init :: proc(lr: ^Loadahead_Reader, r: io.Reader, buf: []byte) -> ^Loadahead_Reader {
lr.r = r
lr.buf = buf
lr.n = 0
return lr
}
lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
return lr.buf[:lr.n]
}
// lookahead_reader_peek returns a slice of the Lookahead_Reader which holds n bytes
// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
// NOTE: The returned buffer is not a copy of the underlying buffer
lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Error) {
switch {
case n < 0:
return nil, .Negative_Read
case n > len(lr.buf):
return nil, .Buffer_Full
}
n := n
err: io.Error
read_count: int
if lr.n < n {
read_count, err = io.read_at_least(lr.r, lr.buf[lr.n:], n-lr.n)
if err == .Unexpected_EOF {
err = .EOF
}
}
lr.n += read_count
if n > lr.n {
n = lr.n
}
return lr.buf[:n], err
}
// lookahead_reader_peek_all returns a slice of the Lookahead_Reader populating the full buffer
// If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
// NOTE: The returned buffer is not a copy of the underlying buffer
lookahead_reader_peek_all :: proc(lr: ^Loadahead_Reader) -> ([]byte, io.Error) {
return lookahead_reader_peek(lr, len(lr.buf))
}
// lookahead_reader_consume drops the first n populated bytes from the Lookahead_Reader.
lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
switch {
case n == 0:
return nil
case n < 0:
return .Negative_Read
case lr.n < n:
return .Short_Buffer
}
copy(lr.buf, lr.buf[n:lr.n])
lr.n -= n
return nil
}
lookahead_reader_consume_all :: proc(lr: ^Loadahead_Reader) -> io.Error {
return lookahead_reader_consume(lr, lr.n)
}
+27 -27
View File
@@ -10,59 +10,59 @@ Read_Writer :: struct {
read_writer_init :: proc(rw: ^Read_Writer, r: ^Reader, w: ^Writer) {
rw.r, rw.w = r, w;
rw.r, rw.w = r, w
}
read_writer_to_stream :: proc(rw: ^Read_Writer) -> (s: io.Stream) {
s.stream_data = rw;
s.stream_vtable = _read_writer_vtable;
return;
s.stream_data = rw
s.stream_vtable = _read_writer_vtable
return
}
@(private)
_read_writer_vtable := &io.Stream_VTable{
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
b := (^Read_Writer)(s.stream_data).r;
return reader_read(b, p);
b := (^Read_Writer)(s.stream_data).r
return reader_read(b, p)
},
impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
b := (^Read_Writer)(s.stream_data).r;
return reader_read_byte(b);
b := (^Read_Writer)(s.stream_data).r
return reader_read_byte(b)
},
impl_unread_byte = proc(s: io.Stream) -> io.Error {
b := (^Read_Writer)(s.stream_data).r;
return reader_unread_byte(b);
b := (^Read_Writer)(s.stream_data).r
return reader_unread_byte(b)
},
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
b := (^Read_Writer)(s.stream_data).r;
return reader_read_rune(b);
b := (^Read_Writer)(s.stream_data).r
return reader_read_rune(b)
},
impl_unread_rune = proc(s: io.Stream) -> io.Error {
b := (^Read_Writer)(s.stream_data).r;
return reader_unread_rune(b);
b := (^Read_Writer)(s.stream_data).r
return reader_unread_rune(b)
},
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
b := (^Read_Writer)(s.stream_data).r;
return reader_write_to(b, w);
b := (^Read_Writer)(s.stream_data).r
return reader_write_to(b, w)
},
impl_flush = proc(s: io.Stream) -> io.Error {
b := (^Read_Writer)(s.stream_data).w;
return writer_flush(b);
b := (^Read_Writer)(s.stream_data).w
return writer_flush(b)
},
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
b := (^Read_Writer)(s.stream_data).w;
return writer_write(b, p);
b := (^Read_Writer)(s.stream_data).w
return writer_write(b, p)
},
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
b := (^Read_Writer)(s.stream_data).w;
return writer_write_byte(b, c);
b := (^Read_Writer)(s.stream_data).w
return writer_write_byte(b, c)
},
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
b := (^Read_Writer)(s.stream_data).w;
return writer_write_rune(b, r);
b := (^Read_Writer)(s.stream_data).w
return writer_write_rune(b, r)
},
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
b := (^Read_Writer)(s.stream_data).w;
return writer_read_from(b, r);
b := (^Read_Writer)(s.stream_data).w
return writer_read_from(b, r)
},
};
}
+183 -177
View File
@@ -17,84 +17,90 @@ Reader :: struct {
last_byte: int, // last byte read, invalid is -1
last_rune_size: int, // size of last rune read, invalid is -1
max_consecutive_empty_reads: int,
}
DEFAULT_BUF_SIZE :: 4096;
DEFAULT_BUF_SIZE :: 4096
@(private)
MIN_READ_BUFFER_SIZE :: 16;
MIN_READ_BUFFER_SIZE :: 16
@(private)
MAX_CONSECUTIVE_EMPTY_READS :: 128;
DEFAULT_MAX_CONSECUTIVE_EMPTY_READS :: 128
reader_init :: proc(b: ^Reader, rd: io.Reader, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator) {
size := size;
size = max(size, MIN_READ_BUFFER_SIZE);
reader_reset(b, rd);
b.buf_allocator = allocator;
b.buf = make([]byte, size, allocator);
size := size
size = max(size, MIN_READ_BUFFER_SIZE)
reader_reset(b, rd)
b.buf_allocator = allocator
b.buf = make([]byte, size, allocator)
}
reader_init_with_buf :: proc(b: ^Reader, rd: io.Reader, buf: []byte) {
reader_reset(b, rd);
b.buf_allocator = {};
b.buf = buf;
reader_reset(b, rd)
b.buf_allocator = {}
b.buf = buf
}
// reader_destroy destroys the underlying buffer with its associated allocator IFF that allocator has been set
reader_destroy :: proc(b: ^Reader) {
delete(b.buf, b.buf_allocator);
b^ = {};
delete(b.buf, b.buf_allocator)
b^ = {}
}
reader_size :: proc(b: ^Reader) -> int {
return len(b.buf);
return len(b.buf)
}
reader_reset :: proc(b: ^Reader, r: io.Reader) {
b.rd = r;
b.r, b.w = 0, 0;
b.err = nil;
b.last_byte = -1;
b.last_rune_size = -1;
b.rd = r
b.r, b.w = 0, 0
b.err = nil
b.last_byte = -1
b.last_rune_size = -1
}
@(private)
_reader_read_new_chunk :: proc(b: ^Reader) -> io.Error {
if b.r > 0 {
copy(b.buf, b.buf[b.r:b.w]);
b.w -= b.r;
b.r = 0;
copy(b.buf, b.buf[b.r:b.w])
b.w -= b.r
b.r = 0
}
if b.w >= len(b.buf) {
return .Buffer_Full;
return .Buffer_Full
}
if b.max_consecutive_empty_reads <= 0 {
b.max_consecutive_empty_reads = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS
}
// read new data, and try a limited number of times
for i := MAX_CONSECUTIVE_EMPTY_READS; i > 0; i -= 1 {
n, err := io.read(b.rd, b.buf[b.w:]);
for i := b.max_consecutive_empty_reads; i > 0; i -= 1 {
n, err := io.read(b.rd, b.buf[b.w:])
if n < 0 {
return .Negative_Read;
return .Negative_Read
}
b.w += n;
b.w += n
if err != nil {
b.err = err;
return nil;
b.err = err
return nil
}
if n > 0 {
return nil;
return nil
}
}
b.err = .No_Progress;
return nil;
b.err = .No_Progress
return nil
}
@(private)
_reader_consume_err :: proc(b: ^Reader) -> io.Error {
err := b.err;
b.err = nil;
return err;
err := b.err
b.err = nil
return err
}
// reader_peek returns the next n bytes without advancing the reader
@@ -103,151 +109,151 @@ _reader_consume_err :: proc(b: ^Reader) -> io.Error {
// explaining why the read is short
// The error will be .Buffer_Full if n is larger than the internal buffer size
reader_peek :: proc(b: ^Reader, n: int) -> (data: []byte, err: io.Error) {
n := n;
n := n
if n < 0 {
return nil, .Negative_Count;
return nil, .Negative_Count
}
b.last_byte = -1;
b.last_rune_size = -1;
b.last_byte = -1
b.last_rune_size = -1
for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
return nil, fill_err;
return nil, fill_err
}
}
if n > len(b.buf) {
return b.buf[b.r : b.w], .Buffer_Full;
return b.buf[b.r : b.w], .Buffer_Full
}
if available := b.w - b.r; available < n {
n = available;
err = _reader_consume_err(b);
n = available
err = _reader_consume_err(b)
if err == nil {
err = .Buffer_Full;
err = .Buffer_Full
}
}
return b.buf[b.r : b.r+n], err;
return b.buf[b.r : b.r+n], err
}
// reader_buffered returns the number of bytes that can be read from the current buffer
reader_buffered :: proc(b: ^Reader) -> int {
return b.w - b.r;
return b.w - b.r
}
// reader_discard skips the next n bytes, and returns the number of bytes that were discarded
reader_discard :: proc(b: ^Reader, n: int) -> (discarded: int, err: io.Error) {
if n < 0 {
return 0, .Negative_Count;
return 0, .Negative_Count
}
if n == 0 {
return;
return
}
remaining := n;
remaining := n
for {
skip := reader_buffered(b);
skip := reader_buffered(b)
if skip == 0 {
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
return 0, fill_err;
return 0, fill_err
}
skip = reader_buffered(b);
skip = reader_buffered(b)
}
skip = min(skip, remaining);
b.r += skip;
remaining -= skip;
skip = min(skip, remaining)
b.r += skip
remaining -= skip
if remaining == 0 {
return n, nil;
return n, nil
}
if b.err != nil {
return n - remaining, _reader_consume_err(b);
return n - remaining, _reader_consume_err(b)
}
}
return;
return
}
// reader_read reads data into p
// The bytes are taken from at most one read on the underlying Reader, which means n may be less than len(p)
reader_read :: proc(b: ^Reader, p: []byte) -> (n: int, err: io.Error) {
n = len(p);
n = len(p)
if n == 0 {
if reader_buffered(b) > 0 {
return 0, nil;
return 0, nil
}
return 0, _reader_consume_err(b);
return 0, _reader_consume_err(b)
}
if b.r == b.w {
if b.err != nil {
return 0, _reader_consume_err(b);
return 0, _reader_consume_err(b)
}
if len(p) >= len(b.buf) {
n, b.err = io.read(b.rd, p);
n, b.err = io.read(b.rd, p)
if n < 0 {
return 0, .Negative_Read;
return 0, .Negative_Read
}
if n > 0 {
b.last_byte = int(p[n-1]);
b.last_rune_size = -1;
b.last_byte = int(p[n-1])
b.last_rune_size = -1
}
return n, _reader_consume_err(b);
return n, _reader_consume_err(b)
}
b.r, b.w = 0, 0;
n, b.err = io.read(b.rd, b.buf);
b.r, b.w = 0, 0
n, b.err = io.read(b.rd, b.buf)
if n < 0 {
return 0, .Negative_Read;
return 0, .Negative_Read
}
if n == 0 {
return 0, _reader_consume_err(b);
return 0, _reader_consume_err(b)
}
b.w += n;
b.w += n
}
n = copy(p, b.buf[b.r:b.w]);
b.r += n;
b.last_byte = int(b.buf[b.r-1]);
b.last_rune_size = -1;
return n, nil;
n = copy(p, b.buf[b.r:b.w])
b.r += n
b.last_byte = int(b.buf[b.r-1])
b.last_rune_size = -1
return n, nil
}
// reader_read_byte reads and returns a single byte
// If no byte is available, it return an error
reader_read_byte :: proc(b: ^Reader) -> (byte, io.Error) {
b.last_rune_size = -1;
b.last_rune_size = -1
for b.r == b.w {
if b.err != nil {
return 0, _reader_consume_err(b);
return 0, _reader_consume_err(b)
}
if err := _reader_read_new_chunk(b); err != nil {
return 0, err;
return 0, err
}
}
c := b.buf[b.r];
b.r += 1;
b.last_byte = int(c);
return c, nil;
c := b.buf[b.r]
b.r += 1
b.last_byte = int(c)
return c, nil
}
// reader_unread_byte unreads the last byte. Only the most recently read byte can be unread
reader_unread_byte :: proc(b: ^Reader) -> io.Error {
if b.last_byte < 0 || b.r == 0 && b.w > 0 {
return .Invalid_Unread;
return .Invalid_Unread
}
if b.r > 0 {
b.r -= 1;
b.r -= 1
} else {
// b.r == 0 && b.w == 0
b.w = 1;
b.w = 1
}
b.buf[b.r] = byte(b.last_byte);
b.last_byte = -1;
b.last_rune_size = -1;
return nil;
b.buf[b.r] = byte(b.last_byte)
b.last_byte = -1
b.last_rune_size = -1
return nil
}
// reader_read_rune reads a single UTF-8 encoded unicode character
@@ -259,96 +265,96 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
b.err == nil &&
b.w-b.w < len(b.buf) {
if err = _reader_read_new_chunk(b); err != nil {
return;
return
}
}
b.last_rune_size = -1;
b.last_rune_size = -1
if b.r == b.w {
err = _reader_consume_err(b);
return;
err = _reader_consume_err(b)
return
}
r, size = rune(b.buf[b.r]), 1;
r, size = rune(b.buf[b.r]), 1
if r >= utf8.RUNE_SELF {
r, size = utf8.decode_rune(b.buf[b.r : b.w]);
r, size = utf8.decode_rune(b.buf[b.r : b.w])
}
b.r += size;
b.last_byte = int(b.buf[b.r-1]);
b.last_rune_size = size;
return;
b.r += size
b.last_byte = int(b.buf[b.r-1])
b.last_rune_size = size
return
}
// reader_unread_rune unreads the last rune. Only the most recently read rune can be unread
reader_unread_rune :: proc(b: ^Reader) -> io.Error {
if b.last_rune_size < 0 || b.r < b.last_rune_size {
return .Invalid_Unread;
return .Invalid_Unread
}
b.r -= b.last_rune_size;
b.last_byte = -1;
b.last_rune_size = -1;
return nil;
b.r -= b.last_rune_size
b.last_byte = -1
b.last_rune_size = -1
return nil
}
reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
write_buf :: proc(b: ^Reader, w: io.Writer) -> (i64, io.Error) {
n, err := io.write(w, b.buf[b.r:b.w]);
n, err := io.write(w, b.buf[b.r:b.w])
if n < 0 {
return 0, .Negative_Write;
return 0, .Negative_Write
}
b.r += n;
return i64(n), err;
b.r += n
return i64(n), err
}
n, err = write_buf(b, w);
n, err = write_buf(b, w)
if err != nil {
return;
return
}
m: i64;
m: i64
if nr, ok := io.to_writer_to(b.rd); ok {
m, err = io.write_to(nr, w);
n += m;
return n, err;
m, err = io.write_to(nr, w)
n += m
return n, err
}
if nw, ok := io.to_reader_from(w); ok {
m, err = io.read_from(nw, b.rd);
n += m;
return n, err;
m, err = io.read_from(nw, b.rd)
n += m
return n, err
}
if b.w-b.r < len(b.buf) {
if err = _reader_read_new_chunk(b); err != nil {
return;
return
}
}
for b.r < b.w {
m, err = write_buf(b, w);
n += m;
m, err = write_buf(b, w)
n += m
if err != nil {
return;
return
}
if err = _reader_read_new_chunk(b); err != nil {
return;
return
}
}
if b.err == .EOF {
b.err = nil;
b.err = nil
}
err = _reader_consume_err(b);
return;
err = _reader_consume_err(b)
return
}
// reader_to_stream converts a Reader into an io.Stream
reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) {
s.stream_data = b;
s.stream_vtable = _reader_vtable;
return;
s.stream_data = b
s.stream_vtable = _reader_vtable
return
}
@@ -356,35 +362,35 @@ reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) {
@(private)
_reader_vtable := &io.Stream_VTable{
impl_destroy = proc(s: io.Stream) -> io.Error {
b := (^Reader)(s.stream_data);
reader_destroy(b);
return nil;
b := (^Reader)(s.stream_data)
reader_destroy(b)
return nil
},
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
b := (^Reader)(s.stream_data);
return reader_read(b, p);
b := (^Reader)(s.stream_data)
return reader_read(b, p)
},
impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
b := (^Reader)(s.stream_data);
return reader_read_byte(b);
b := (^Reader)(s.stream_data)
return reader_read_byte(b)
},
impl_unread_byte = proc(s: io.Stream) -> io.Error {
b := (^Reader)(s.stream_data);
return reader_unread_byte(b);
b := (^Reader)(s.stream_data)
return reader_unread_byte(b)
},
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
b := (^Reader)(s.stream_data);
return reader_read_rune(b);
b := (^Reader)(s.stream_data)
return reader_read_rune(b)
},
impl_unread_rune = proc(s: io.Stream) -> io.Error {
b := (^Reader)(s.stream_data);
return reader_unread_rune(b);
b := (^Reader)(s.stream_data)
return reader_unread_rune(b)
},
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
b := (^Reader)(s.stream_data);
return reader_write_to(b, w);
b := (^Reader)(s.stream_data)
return reader_write_to(b, w)
},
};
}
@@ -404,71 +410,71 @@ _reader_vtable := &io.Stream_VTable{
// reader_read_slice returns err != nil if and only if line does not end in delim
//
reader_read_slice :: proc(b: ^Reader, delim: byte) -> (line: []byte, err: io.Error) {
s := 0;
s := 0
for {
if i := bytes.index_byte(b.buf[b.r+s : b.w], delim); i >= 0 {
i += s;
line = b.buf[b.r:][:i+1];
b.r += i + 1;
break;
i += s
line = b.buf[b.r:][:i+1]
b.r += i + 1
break
}
if b.err != nil {
line = b.buf[b.r : b.w];
b.r = b.w;
err = _reader_consume_err(b);
break;
line = b.buf[b.r : b.w]
b.r = b.w
err = _reader_consume_err(b)
break
}
if reader_buffered(b) >= len(b.buf) {
b.r = b.w;
line = b.buf;
err = .Buffer_Full;
break;
b.r = b.w
line = b.buf
err = .Buffer_Full
break
}
s = b.w - b.r;
s = b.w - b.r
if err = _reader_read_new_chunk(b); err != nil {
break;
break
}
}
if i := len(line)-1; i >= 0 {
b.last_byte = int(line[i]);
b.last_rune_size = -1;
b.last_byte = int(line[i])
b.last_rune_size = -1
}
return;
return
}
// reader_read_bytes reads until the first occurrence of delim from the Reader
// It returns an allocated slice containing the data up to and including the delimiter
reader_read_bytes :: proc(b: ^Reader, delim: byte, allocator := context.allocator) -> (buf: []byte, err: io.Error) {
full: [dynamic]byte;
full.allocator = allocator;
full: [dynamic]byte
full.allocator = allocator
frag: []byte;
frag: []byte
for {
e: io.Error;
frag, e = reader_read_slice(b, delim);
e: io.Error
frag, e = reader_read_slice(b, delim)
if e == nil {
break;
break
}
if e != .Buffer_Full {
err = e;
break;
err = e
break
}
append(&full, ..frag);
append(&full, ..frag)
}
append(&full, ..frag);
return full[:], err;
append(&full, ..frag)
return full[:], err
}
// reader_read_string reads until the first occurrence of delim from the Reader
// It returns an allocated string containing the data up to and including the delimiter
reader_read_string :: proc(b: ^Reader, delim: byte, allocator := context.allocator) -> (string, io.Error) {
buf, err := reader_read_bytes(b, delim, allocator);
return string(buf), err;
buf, err := reader_read_bytes(b, delim, allocator)
return string(buf), err
}
+337
View File
@@ -0,0 +1,337 @@
package bufio
import "core:bytes"
import "core:io"
import "core:mem"
import "core:unicode/utf8"
import "core:intrinsics"
// Extra errors returns by scanning procedures
Scanner_Extra_Error :: enum i32 {
None,
Negative_Advance,
Advanced_Too_Far,
Bad_Read_Count,
Too_Long,
Too_Short,
}
Scanner_Error :: union #shared_nil {
io.Error,
Scanner_Extra_Error,
}
// Split_Proc is the signature of the split procedure used to tokenize the input.
Split_Proc :: proc(data: []byte, at_eof: bool) -> (advance: int, token: []byte, err: Scanner_Error, final_token: bool)
Scanner :: struct {
r: io.Reader,
split: Split_Proc,
buf: [dynamic]byte,
max_token_size: int,
start: int,
end: int,
token: []byte,
_err: Scanner_Error,
max_consecutive_empty_reads: int,
successive_empty_token_count: int,
scan_called: bool,
done: bool,
}
DEFAULT_MAX_SCAN_TOKEN_SIZE :: 1<<16
@(private)
_INIT_BUF_SIZE :: 4096
scanner_init :: proc(s: ^Scanner, r: io.Reader, buf_allocator := context.allocator) -> ^Scanner {
s.r = r
s.split = scan_lines
s.max_token_size = DEFAULT_MAX_SCAN_TOKEN_SIZE
s.buf.allocator = buf_allocator
return s
}
scanner_init_with_buffer :: proc(s: ^Scanner, r: io.Reader, buf: []byte) -> ^Scanner {
s.r = r
s.split = scan_lines
s.max_token_size = DEFAULT_MAX_SCAN_TOKEN_SIZE
s.buf = mem.buffer_from_slice(buf)
resize(&s.buf, cap(s.buf))
return s
}
scanner_destroy :: proc(s: ^Scanner) {
delete(s.buf)
}
// Returns the first non-EOF error that was encounted by the scanner
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
switch s._err {
case .EOF, nil:
return nil
}
return s._err
}
// Returns the most recent token created by scanner_scan.
// The underlying array may point to data that may be overwritten
// by another call to scanner_scan.
// Treat the returned value as if it is immutable.
scanner_bytes :: proc(s: ^Scanner) -> []byte {
return s.token
}
// Returns the most recent token created by scanner_scan.
// The underlying array may point to data that may be overwritten
// by another call to scanner_scan.
// Treat the returned value as if it is immutable.
scanner_text :: proc(s: ^Scanner) -> string {
return string(s.token)
}
// scanner_scan advances the scanner
scanner_scan :: proc(s: ^Scanner) -> bool {
set_err :: proc(s: ^Scanner, err: Scanner_Error) {
switch s._err {
case nil, .EOF:
s._err = err
}
}
if s.done {
return false
}
s.scan_called = true
for {
// Check if a token is possible with what is available
// Allow the split procedure to recover if it fails
if s.start < s.end || s._err != nil {
advance, token, err, final_token := s.split(s.buf[s.start:s.end], s._err != nil)
if final_token {
s.token = token
s.done = true
return true
}
if err != nil {
set_err(s, err)
return false
}
// Do advance
if advance < 0 {
set_err(s, .Negative_Advance)
return false
}
if advance > s.end-s.start {
set_err(s, .Advanced_Too_Far)
return false
}
s.start += advance
s.token = token
if s.token != nil {
if s._err == nil || advance > 0 {
s.successive_empty_token_count = 0
} else {
s.successive_empty_token_count += 1
if s.max_consecutive_empty_reads <= 0 {
s.max_consecutive_empty_reads = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS
}
if s.successive_empty_token_count > s.max_consecutive_empty_reads {
set_err(s, .No_Progress)
return false
}
}
return true
}
}
// If an error is hit, no token can be created
if s._err != nil {
s.start = 0
s.end = 0
return false
}
// More data must be required to be read
if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
copy(s.buf[:], s.buf[s.start:s.end])
s.end -= s.start
s.start = 0
}
could_be_too_short := false
// Resize the buffer if full
if s.end == len(s.buf) {
if s.max_token_size <= 0 {
s.max_token_size = DEFAULT_MAX_SCAN_TOKEN_SIZE
}
if len(s.buf) >= s.max_token_size {
set_err(s, .Too_Long)
return false
}
// overflow check
new_size := _INIT_BUF_SIZE
if len(s.buf) > 0 {
overflowed: bool
if new_size, overflowed = intrinsics.overflow_mul(len(s.buf), 2); overflowed {
set_err(s, .Too_Long)
return false
}
}
old_size := len(s.buf)
new_size = min(new_size, s.max_token_size)
resize(&s.buf, new_size)
s.end -= s.start
s.start = 0
could_be_too_short = old_size >= len(s.buf)
}
// Read data into the buffer
loop := 0
for {
n, err := io.read(s.r, s.buf[s.end:len(s.buf)])
if n < 0 || len(s.buf)-s.end < n {
set_err(s, .Bad_Read_Count)
break
}
s.end += n
if err != nil {
set_err(s, err)
break
}
if n > 0 {
s.successive_empty_token_count = 0
break
}
loop += 1
if s.max_consecutive_empty_reads <= 0 {
s.max_consecutive_empty_reads = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS
}
if loop > s.max_consecutive_empty_reads {
if could_be_too_short {
set_err(s, .Too_Short)
} else {
set_err(s, .No_Progress)
}
break
}
}
}
}
scan_bytes :: proc(data: []byte, at_eof: bool) -> (advance: int, token: []byte, err: Scanner_Error, final_token: bool) {
if at_eof && len(data) == 0 {
return
}
return 1, data[0:1], nil, false
}
scan_runes :: proc(data: []byte, at_eof: bool) -> (advance: int, token: []byte, err: Scanner_Error, final_token: bool) {
if at_eof && len(data) == 0 {
return
}
if data[0] < utf8.RUNE_SELF {
advance = 1
token = data[0:1]
return
}
_, width := utf8.decode_rune(data)
if width > 1 {
advance = width
token = data[0:width]
return
}
if !at_eof && !utf8.full_rune(data) {
return
}
@thread_local ERROR_RUNE := []byte{0xef, 0xbf, 0xbd}
advance = 1
token = ERROR_RUNE
return
}
scan_words :: proc(data: []byte, at_eof: bool) -> (advance: int, token: []byte, err: Scanner_Error, final_token: bool) {
is_space :: proc "contextless" (r: rune) -> bool {
switch r {
// lower ones
case ' ', '\t', '\n', '\v', '\f', '\r':
return true
case '\u0085', '\u00a0':
return true
// higher ones
case '\u2000' ..= '\u200a':
return true
case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
return true
}
return false
}
// skip spaces at the beginning
start := 0
for width := 0; start < len(data); start += width {
r: rune
r, width = utf8.decode_rune(data[start:])
if !is_space(r) {
break
}
}
for width, i := 0, start; i < len(data); i += width {
r: rune
r, width = utf8.decode_rune(data[i:])
if is_space(r) {
advance = i+width
token = data[start:i]
return
}
}
if at_eof && len(data) > start {
advance = len(data)
token = data[start:]
return
}
advance = start
return
}
scan_lines :: proc(data: []byte, at_eof: bool) -> (advance: int, token: []byte, err: Scanner_Error, final_token: bool) {
trim_carriage_return :: proc "contextless" (data: []byte) -> []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0:len(data)-1]
}
return data
}
if at_eof && len(data) == 0 {
return
}
if i := bytes.index_byte(data, '\n'); i >= 0 {
advance = i+1
token = trim_carriage_return(data[0:i])
return
}
if at_eof {
advance = len(data)
token = trim_carriage_return(data)
}
return
}
+103 -99
View File
@@ -15,153 +15,155 @@ Writer :: struct {
err: io.Error,
max_consecutive_empty_writes: int,
}
writer_init :: proc(b: ^Writer, wr: io.Writer, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator) {
size := size;
size = max(size, MIN_READ_BUFFER_SIZE);
writer_reset(b, wr);
b.buf_allocator = allocator;
b.buf = make([]byte, size, allocator);
size := size
size = max(size, MIN_READ_BUFFER_SIZE)
writer_reset(b, wr)
b.buf_allocator = allocator
b.buf = make([]byte, size, allocator)
}
writer_init_with_buf :: proc(b: ^Writer, wr: io.Writer, buf: []byte) {
writer_reset(b, wr);
b.buf_allocator = {};
b.buf = buf;
writer_reset(b, wr)
b.buf_allocator = {}
b.buf = buf
}
// writer_destroy destroys the underlying buffer with its associated allocator IFF that allocator has been set
writer_destroy :: proc(b: ^Writer) {
delete(b.buf, b.buf_allocator);
b^ = {};
delete(b.buf, b.buf_allocator)
b^ = {}
}
// writer_size returns the size of underlying buffer in bytes
writer_size :: proc(b: ^Writer) -> int {
return len(b.buf);
return len(b.buf)
}
writer_reset :: proc(b: ^Writer, w: io.Writer) {
b.wr = w;
b.n = 0;
b.err = nil;
b.wr = w
b.n = 0
b.err = nil
}
// writer_flush writes any buffered data into the underlying io.Writer
writer_flush :: proc(b: ^Writer) -> io.Error {
if b.err != nil {
return b.err;
return b.err
}
if b.n == 0 {
return nil;
return nil
}
n, err := io.write(b.wr, b.buf[0:b.n]);
n, err := io.write(b.wr, b.buf[0:b.n])
if n < b.n && err == nil {
err = .Short_Write;
err = .Short_Write
}
if err != nil {
if n > 0 && n < b.n {
copy(b.buf[:b.n-n], b.buf[n : b.n]);
copy(b.buf[:b.n-n], b.buf[n : b.n])
}
b.n -= n;
b.err = err;
return err;
b.n -= n
b.err = err
return err
}
b.n = 0;
return nil;
b.n = 0
return nil
}
// writer_available returns how many bytes are unused in the buffer
writer_available :: proc(b: ^Writer) -> int {
return len(b.buf) - b.n;
return len(b.buf) - b.n
}
// writer_buffered returns the number of bytes that have been writted into the current buffer
writer_buffered :: proc(b: ^Writer) -> int {
return b.n;
return b.n
}
// writer_write writes the contents of p into the buffer
// It returns the number of bytes written
// If n < len(p), it will return an error explaining why the write is short
writer_write :: proc(b: ^Writer, p: []byte) -> (n: int, err: io.Error) {
p := p;
p := p
for len(p) > writer_available(b) && b.err == nil {
m: int;
m: int
if writer_buffered(b) == 0 {
m, b.err = io.write(b.wr, p);
m, b.err = io.write(b.wr, p)
} else {
m = copy(b.buf[b.n:], p);
b.n += m;
writer_flush(b);
m = copy(b.buf[b.n:], p)
b.n += m
writer_flush(b)
}
n += m;
p = p[m:];
n += m
p = p[m:]
}
if b.err != nil {
return n, b.err;
return n, b.err
}
m := copy(b.buf[b.n:], p);
b.n += m;
m += n;
return m, nil;
m := copy(b.buf[b.n:], p)
b.n += m
m += n
return m, nil
}
// writer_write_byte writes a single byte
writer_write_byte :: proc(b: ^Writer, c: byte) -> io.Error {
if b.err != nil {
return b.err;
return b.err
}
if writer_available(b) <= 0 && writer_flush(b) != nil {
return b.err;
return b.err
}
b.buf[b.n] = c;
b.n += 1;
return nil;
b.buf[b.n] = c
b.n += 1
return nil
}
// writer_write_rune writes a single unicode code point, and returns the number of bytes written with any error
writer_write_rune :: proc(b: ^Writer, r: rune) -> (size: int, err: io.Error) {
if r < utf8.RUNE_SELF {
err = writer_write_byte(b, byte(r));
size = 0 if err != nil else 1;
return;
err = writer_write_byte(b, byte(r))
size = 0 if err != nil else 1
return
}
if b.err != nil {
return 0, b.err;
return 0, b.err
}
buf: [4]u8;
buf: [4]u8
n := writer_available(b);
n := writer_available(b)
if n < utf8.UTF_MAX {
writer_flush(b);
writer_flush(b)
if b.err != nil {
return 0, b.err;
return 0, b.err
}
n = writer_available(b);
n = writer_available(b)
if n < utf8.UTF_MAX {
// this only happens if the buffer is very small
w: int;
buf, w = utf8.encode_rune(r);
return writer_write(b, buf[:w]);
w: int
buf, w = utf8.encode_rune(r)
return writer_write(b, buf[:w])
}
}
buf, size = utf8.encode_rune(r);
copy(b.buf[b.n:], buf[:size]);
b.n += size;
return;
buf, size = utf8.encode_rune(r)
copy(b.buf[b.n:], buf[:size])
b.n += size
return
}
// writer_write writes a string into the buffer
// It returns the number of bytes written
// If n < len(p), it will return an error explaining why the write is short
writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) {
return writer_write(b, transmute([]byte)s);
return writer_write(b, transmute([]byte)s)
}
// writer_read_from is to support io.Reader_From types
@@ -169,58 +171,60 @@ writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) {
// this procedure calls the underlying read_from implementation without buffering
writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
if b.err != nil {
return 0, b.err;
return 0, b.err
}
if writer_buffered(b) == 0 {
if w, ok := io.to_reader_from(b.wr); !ok {
n, err = io.read_from(w, r);
b.err = err;
return;
n, err = io.read_from(w, r)
b.err = err
return
}
}
for {
if writer_available(b) == 0 {
if ferr := writer_flush(b); ferr != nil {
return n, ferr;
}
writer_flush(b) or_return
}
m: int;
nr := 0;
for nr < MAX_CONSECUTIVE_EMPTY_READS {
m, err = io.read(r, b.buf[b.n:]);
if b.max_consecutive_empty_writes <= 0 {
b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS
}
m: int
nr := 0
for nr < b.max_consecutive_empty_writes {
m, err = io.read(r, b.buf[b.n:])
if m != 0 || err != nil {
break;
break
}
nr += 1;
nr += 1
}
if nr == MAX_CONSECUTIVE_EMPTY_READS {
return n, .No_Progress;
if nr == b.max_consecutive_empty_writes {
return n, .No_Progress
}
b.n += m;
n += i64(m);
b.n += m
n += i64(m)
if err != nil {
break;
break
}
}
if err == .EOF {
if writer_available(b) == 0 {
err = writer_flush(b);
err = writer_flush(b)
} else {
err = nil;
err = nil
}
}
return;
return
}
// writer_to_stream converts a Writer into an io.Stream
writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) {
s.stream_data = b;
s.stream_vtable = _writer_vtable;
return;
s.stream_data = b
s.stream_vtable = _writer_vtable
return
}
@@ -228,28 +232,28 @@ writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) {
@(private)
_writer_vtable := &io.Stream_VTable{
impl_destroy = proc(s: io.Stream) -> io.Error {
b := (^Writer)(s.stream_data);
writer_destroy(b);
return nil;
b := (^Writer)(s.stream_data)
writer_destroy(b)
return nil
},
impl_flush = proc(s: io.Stream) -> io.Error {
b := (^Writer)(s.stream_data);
return writer_flush(b);
b := (^Writer)(s.stream_data)
return writer_flush(b)
},
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
b := (^Writer)(s.stream_data);
return writer_write(b, p);
b := (^Writer)(s.stream_data)
return writer_write(b, p)
},
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
b := (^Writer)(s.stream_data);
return writer_write_byte(b, c);
b := (^Writer)(s.stream_data)
return writer_write_byte(b, c)
},
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
b := (^Writer)(s.stream_data);
return writer_write_rune(b, r);
b := (^Writer)(s.stream_data)
return writer_write_rune(b, r)
},
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
b := (^Writer)(s.stream_data);
return writer_read_from(b, r);
b := (^Writer)(s.stream_data)
return writer_read_from(b, r)
},
};
}
+1 -1
View File
@@ -2,7 +2,7 @@
package builtin
nil :: nil;
false :: 0!==0;
false :: 0!=0;
true :: 0==0;
ODIN_OS :: ODIN_OS;
+187 -187
View File
@@ -3,10 +3,10 @@ package bytes
import "core:io"
import "core:unicode/utf8"
MIN_READ :: 512;
MIN_READ :: 512
@(private)
SMALL_BUFFER_SIZE :: 64;
SMALL_BUFFER_SIZE :: 64
// A Buffer is a variable-sized buffer of bytes with a io.Stream interface
// The zero value for Buffer is an empty buffer ready to use.
@@ -28,406 +28,406 @@ Read_Op :: enum i8 {
buffer_init :: proc(b: ^Buffer, buf: []byte) {
resize(&b.buf, len(buf));
copy(b.buf[:], buf);
resize(&b.buf, len(buf))
copy(b.buf[:], buf)
}
buffer_init_string :: proc(b: ^Buffer, s: string) {
resize(&b.buf, len(s));
copy(b.buf[:], s);
resize(&b.buf, len(s))
copy(b.buf[:], s)
}
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
b.buf.allocator = allocator;
reserve(&b.buf, cap);
resize(&b.buf, len);
b.buf.allocator = allocator
reserve(&b.buf, cap)
resize(&b.buf, len)
}
buffer_destroy :: proc(b: ^Buffer) {
delete(b.buf);
buffer_reset(b);
delete(b.buf)
buffer_reset(b)
}
buffer_to_bytes :: proc(b: ^Buffer) -> []byte {
return b.buf[b.off:];
return b.buf[b.off:]
}
buffer_to_string :: proc(b: ^Buffer) -> string {
if b == nil {
return "<nil>";
return "<nil>"
}
return string(b.buf[b.off:]);
return string(b.buf[b.off:])
}
buffer_is_empty :: proc(b: ^Buffer) -> bool {
return len(b.buf) <= b.off;
return len(b.buf) <= b.off
}
buffer_length :: proc(b: ^Buffer) -> int {
return len(b.buf) - b.off;
return len(b.buf) - b.off
}
buffer_capacity :: proc(b: ^Buffer) -> int {
return cap(b.buf);
return cap(b.buf)
}
buffer_reset :: proc(b: ^Buffer) {
clear(&b.buf);
b.off = 0;
b.last_read = .Invalid;
clear(&b.buf)
b.off = 0
b.last_read = .Invalid
}
buffer_truncate :: proc(b: ^Buffer, n: int) {
if n == 0 {
buffer_reset(b);
return;
buffer_reset(b)
return
}
b.last_read = .Invalid;
b.last_read = .Invalid
if n < 0 || n > buffer_length(b) {
panic("bytes.truncate: truncation out of range");
panic("bytes.truncate: truncation out of range")
}
resize(&b.buf, b.off+n);
resize(&b.buf, b.off+n)
}
@(private)
_buffer_try_grow :: proc(b: ^Buffer, n: int) -> (int, bool) {
if l := len(b.buf); n <= cap(b.buf)-l {
resize(&b.buf, l+n);
return l, true;
resize(&b.buf, l+n)
return l, true
}
return 0, false;
return 0, false
}
@(private)
_buffer_grow :: proc(b: ^Buffer, n: int) -> int {
m := buffer_length(b);
m := buffer_length(b)
if m == 0 && b.off != 0 {
buffer_reset(b);
buffer_reset(b)
}
if i, ok := _buffer_try_grow(b, n); ok {
return i;
return i
}
if b.buf == nil && n <= SMALL_BUFFER_SIZE {
b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE);
return 0;
b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE)
return 0
}
c := cap(b.buf);
c := cap(b.buf)
if n <= c/2 - m {
copy(b.buf[:], b.buf[b.off:]);
copy(b.buf[:], b.buf[b.off:])
} else if c > max(int) - c - n {
panic("bytes.Buffer: too large");
panic("bytes.Buffer: too large")
} else {
resize(&b.buf, 2*c + n);
copy(b.buf[:], b.buf[b.off:]);
resize(&b.buf, 2*c + n)
copy(b.buf[:], b.buf[b.off:])
}
b.off = 0;
resize(&b.buf, m+n);
return m;
b.off = 0
resize(&b.buf, m+n)
return m
}
buffer_grow :: proc(b: ^Buffer, n: int) {
if n < 0 {
panic("bytes.buffer_grow: negative count");
panic("bytes.buffer_grow: negative count")
}
m := _buffer_grow(b, n);
resize(&b.buf, m);
m := _buffer_grow(b, n)
resize(&b.buf, m)
}
buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
b.last_read = .Invalid;
b.last_read = .Invalid
if offset < 0 {
err = .Invalid_Offset;
return;
err = .Invalid_Offset
return
}
_, ok := _buffer_try_grow(b, offset+len(p));
_, ok := _buffer_try_grow(b, offset+len(p))
if !ok {
_ = _buffer_grow(b, offset+len(p));
_ = _buffer_grow(b, offset+len(p))
}
if len(b.buf) <= offset {
return 0, .Short_Write;
return 0, .Short_Write
}
return copy(b.buf[offset:], p), nil;
return copy(b.buf[offset:], p), nil
}
buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
b.last_read = .Invalid;
m, ok := _buffer_try_grow(b, len(p));
b.last_read = .Invalid
m, ok := _buffer_try_grow(b, len(p))
if !ok {
m = _buffer_grow(b, len(p));
m = _buffer_grow(b, len(p))
}
return copy(b.buf[m:], p), nil;
return copy(b.buf[m:], p), nil
}
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
b.last_read = .Invalid;
m, ok := _buffer_try_grow(b, len(s));
b.last_read = .Invalid
m, ok := _buffer_try_grow(b, len(s))
if !ok {
m = _buffer_grow(b, len(s));
m = _buffer_grow(b, len(s))
}
return copy(b.buf[m:], s), nil;
return copy(b.buf[m:], s), nil
}
buffer_write_byte :: proc(b: ^Buffer, c: byte) -> io.Error {
b.last_read = .Invalid;
m, ok := _buffer_try_grow(b, 1);
b.last_read = .Invalid
m, ok := _buffer_try_grow(b, 1)
if !ok {
m = _buffer_grow(b, 1);
m = _buffer_grow(b, 1)
}
b.buf[m] = c;
return nil;
b.buf[m] = c
return nil
}
buffer_write_rune :: proc(b: ^Buffer, r: rune) -> (n: int, err: io.Error) {
if r < utf8.RUNE_SELF {
buffer_write_byte(b, byte(r));
return 1, nil;
buffer_write_byte(b, byte(r))
return 1, nil
}
b.last_read = .Invalid;
m, ok := _buffer_try_grow(b, utf8.UTF_MAX);
b.last_read = .Invalid
m, ok := _buffer_try_grow(b, utf8.UTF_MAX)
if !ok {
m = _buffer_grow(b, utf8.UTF_MAX);
m = _buffer_grow(b, utf8.UTF_MAX)
}
res: [4]byte;
res, n = utf8.encode_rune(r);
copy(b.buf[m:][:utf8.UTF_MAX], res[:n]);
resize(&b.buf, m+n);
return;
res: [4]byte
res, n = utf8.encode_rune(r)
copy(b.buf[m:][:utf8.UTF_MAX], res[:n])
resize(&b.buf, m+n)
return
}
buffer_next :: proc(b: ^Buffer, n: int) -> []byte {
n := n;
b.last_read = .Invalid;
m := buffer_length(b);
n := n
b.last_read = .Invalid
m := buffer_length(b)
if n > m {
n = m;
n = m
}
data := b.buf[b.off : b.off + n];
b.off += n;
data := b.buf[b.off : b.off + n]
b.off += n
if n > 0 {
b.last_read = .Read;
b.last_read = .Read
}
return data;
return data
}
buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
b.last_read = .Invalid;
b.last_read = .Invalid
if buffer_is_empty(b) {
buffer_reset(b);
buffer_reset(b)
if len(p) == 0 {
return 0, nil;
return 0, nil
}
return 0, .EOF;
return 0, .EOF
}
n = copy(p, b.buf[b.off:]);
b.off += n;
n = copy(p, b.buf[b.off:])
b.off += n
if n > 0 {
b.last_read = .Read;
b.last_read = .Read
}
return;
return
}
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
b.last_read = .Invalid;
b.last_read = .Invalid
if offset < 0 || offset >= len(b.buf) {
err = .Invalid_Offset;
return;
err = .Invalid_Offset
return
}
if 0 <= offset && offset < len(b.buf) {
n = copy(p, b.buf[offset:]);
n = copy(p, b.buf[offset:])
}
if n > 0 {
b.last_read = .Read;
b.last_read = .Read
}
return;
return
}
buffer_read_byte :: proc(b: ^Buffer) -> (byte, io.Error) {
if buffer_is_empty(b) {
buffer_reset(b);
return 0, .EOF;
buffer_reset(b)
return 0, .EOF
}
c := b.buf[b.off];
b.off += 1;
b.last_read = .Read;
return c, nil;
c := b.buf[b.off]
b.off += 1
b.last_read = .Read
return c, nil
}
buffer_read_rune :: proc(b: ^Buffer) -> (r: rune, size: int, err: io.Error) {
if buffer_is_empty(b) {
buffer_reset(b);
return 0, 0, .EOF;
buffer_reset(b)
return 0, 0, .EOF
}
c := b.buf[b.off];
c := b.buf[b.off]
if c < utf8.RUNE_SELF {
b.off += 1;
b.last_read = .Read_Rune1;
return rune(c), 1, nil;
b.off += 1
b.last_read = .Read_Rune1
return rune(c), 1, nil
}
r, size = utf8.decode_rune(b.buf[b.off:]);
b.off += size;
b.last_read = Read_Op(i8(size));
return;
r, size = utf8.decode_rune(b.buf[b.off:])
b.off += size
b.last_read = Read_Op(i8(size))
return
}
buffer_unread_byte :: proc(b: ^Buffer) -> io.Error {
if b.last_read == .Invalid {
return .Invalid_Unread;
return .Invalid_Unread
}
b.last_read = .Invalid;
b.last_read = .Invalid
if b.off > 0 {
b.off -= 1;
b.off -= 1
}
return nil;
return nil
}
buffer_unread_rune :: proc(b: ^Buffer) -> io.Error {
if b.last_read <= .Invalid {
return .Invalid_Unread;
return .Invalid_Unread
}
if b.off >= int(b.last_read) {
b.off -= int(i8(b.last_read));
b.off -= int(i8(b.last_read))
}
b.last_read = .Invalid;
return nil;
b.last_read = .Invalid
return nil
}
buffer_read_bytes :: proc(b: ^Buffer, delim: byte) -> (line: []byte, err: io.Error) {
i := index_byte(b.buf[b.off:], delim);
end := b.off + i + 1;
i := index_byte(b.buf[b.off:], delim)
end := b.off + i + 1
if i < 0 {
end = len(b.buf);
err = .EOF;
end = len(b.buf)
err = .EOF
}
line = b.buf[b.off:end];
b.off = end;
b.last_read = .Read;
return;
line = b.buf[b.off:end]
b.off = end
b.last_read = .Read
return
}
buffer_read_string :: proc(b: ^Buffer, delim: byte) -> (line: string, err: io.Error) {
slice: []byte;
slice, err = buffer_read_bytes(b, delim);
return string(slice), err;
slice: []byte
slice, err = buffer_read_bytes(b, delim)
return string(slice), err
}
buffer_write_to :: proc(b: ^Buffer, w: io.Writer) -> (n: i64, err: io.Error) {
b.last_read = .Invalid;
b.last_read = .Invalid
if byte_count := buffer_length(b); byte_count > 0 {
m, e := io.write(w, b.buf[b.off:]);
m, e := io.write(w, b.buf[b.off:])
if m > byte_count {
panic("bytes.buffer_write_to: invalid io.write count");
panic("bytes.buffer_write_to: invalid io.write count")
}
b.off += m;
n = i64(m);
b.off += m
n = i64(m)
if e != nil {
err = e;
return;
err = e
return
}
if m != byte_count {
err = .Short_Write;
return;
err = .Short_Write
return
}
}
buffer_reset(b);
return;
buffer_reset(b)
return
}
buffer_read_from :: proc(b: ^Buffer, r: io.Reader) -> (n: i64, err: io.Error) #no_bounds_check {
b.last_read = .Invalid;
b.last_read = .Invalid
for {
i := _buffer_grow(b, MIN_READ);
resize(&b.buf, i);
m, e := io.read(r, b.buf[i:cap(b.buf)]);
i := _buffer_grow(b, MIN_READ)
resize(&b.buf, i)
m, e := io.read(r, b.buf[i:cap(b.buf)])
if m < 0 {
err = .Negative_Read;
return;
err = .Negative_Read
return
}
resize(&b.buf, i+m);
n += i64(m);
resize(&b.buf, i+m)
n += i64(m)
if e == .EOF {
return;
return
}
if e != nil {
err = e;
return;
err = e
return
}
}
return;
return
}
buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) {
s.stream_data = b;
s.stream_vtable = _buffer_vtable;
return;
s.stream_data = b
s.stream_vtable = _buffer_vtable
return
}
@(private)
_buffer_vtable := &io.Stream_VTable{
impl_size = proc(s: io.Stream) -> i64 {
b := (^Buffer)(s.stream_data);
return i64(buffer_capacity(b));
b := (^Buffer)(s.stream_data)
return i64(buffer_capacity(b))
},
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_read(b, p);
b := (^Buffer)(s.stream_data)
return buffer_read(b, p)
},
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_read_at(b, p, int(offset));
b := (^Buffer)(s.stream_data)
return buffer_read_at(b, p, int(offset))
},
impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_read_byte(b);
b := (^Buffer)(s.stream_data)
return buffer_read_byte(b)
},
impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_read_rune(b);
b := (^Buffer)(s.stream_data)
return buffer_read_rune(b)
},
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_write(b, p);
b := (^Buffer)(s.stream_data)
return buffer_write(b, p)
},
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_write_at(b, p, int(offset));
b := (^Buffer)(s.stream_data)
return buffer_write_at(b, p, int(offset))
},
impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error {
b := (^Buffer)(s.stream_data);
return buffer_write_byte(b, c);
b := (^Buffer)(s.stream_data)
return buffer_write_byte(b, c)
},
impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_write_rune(b, r);
b := (^Buffer)(s.stream_data)
return buffer_write_rune(b, r)
},
impl_unread_byte = proc(s: io.Stream) -> io.Error {
b := (^Buffer)(s.stream_data);
return buffer_unread_byte(b);
b := (^Buffer)(s.stream_data)
return buffer_unread_byte(b)
},
impl_unread_rune = proc(s: io.Stream) -> io.Error {
b := (^Buffer)(s.stream_data);
return buffer_unread_rune(b);
b := (^Buffer)(s.stream_data)
return buffer_unread_rune(b)
},
impl_destroy = proc(s: io.Stream) -> io.Error {
b := (^Buffer)(s.stream_data);
buffer_destroy(b);
return nil;
b := (^Buffer)(s.stream_data)
buffer_destroy(b)
return nil
},
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_write_to(b, w);
b := (^Buffer)(s.stream_data)
return buffer_write_to(b, w)
},
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_read_from(b, r);
b := (^Buffer)(s.stream_data)
return buffer_read_from(b, r)
},
};
}
+415 -440
View File
File diff suppressed because it is too large Load Diff
+79 -79
View File
@@ -10,168 +10,168 @@ Reader :: struct {
}
reader_init :: proc(r: ^Reader, s: []byte) {
r.s = s;
r.i = 0;
r.prev_rune = -1;
r.s = s
r.i = 0
r.prev_rune = -1
}
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
s.stream_data = r;
s.stream_vtable = _reader_vtable;
return;
s.stream_data = r
s.stream_vtable = _reader_vtable
return
}
reader_length :: proc(r: ^Reader) -> int {
if r.i >= i64(len(r.s)) {
return 0;
return 0
}
return int(i64(len(r.s)) - r.i);
return int(i64(len(r.s)) - r.i)
}
reader_size :: proc(r: ^Reader) -> i64 {
return i64(len(r.s));
return i64(len(r.s))
}
reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
if r.i >= i64(len(r.s)) {
return 0, .EOF;
return 0, .EOF
}
r.prev_rune = -1;
n = copy(p, r.s[r.i:]);
r.i += i64(n);
return;
r.prev_rune = -1
n = copy(p, r.s[r.i:])
r.i += i64(n)
return
}
reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) {
if off < 0 {
return 0, .Invalid_Offset;
return 0, .Invalid_Offset
}
if off >= i64(len(r.s)) {
return 0, .EOF;
return 0, .EOF
}
n = copy(p, r.s[off:]);
n = copy(p, r.s[off:])
if n < len(p) {
err = .EOF;
err = .EOF
}
return;
return
}
reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) {
r.prev_rune = -1;
r.prev_rune = -1
if r.i >= i64(len(r.s)) {
return 0, .EOF;
return 0, .EOF
}
b := r.s[r.i];
r.i += 1;
return b, nil;
b := r.s[r.i]
r.i += 1
return b, nil
}
reader_unread_byte :: proc(r: ^Reader) -> io.Error {
if r.i <= 0 {
return .Invalid_Unread;
return .Invalid_Unread
}
r.prev_rune = -1;
r.i -= 1;
return nil;
r.prev_rune = -1
r.i -= 1
return nil
}
reader_read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: io.Error) {
if r.i >= i64(len(r.s)) {
r.prev_rune = -1;
return 0, 0, .EOF;
r.prev_rune = -1
return 0, 0, .EOF
}
r.prev_rune = int(r.i);
r.prev_rune = int(r.i)
if c := r.s[r.i]; c < utf8.RUNE_SELF {
r.i += 1;
return rune(c), 1, nil;
r.i += 1
return rune(c), 1, nil
}
ch, size = utf8.decode_rune(r.s[r.i:]);
r.i += i64(size);
return;
ch, size = utf8.decode_rune(r.s[r.i:])
r.i += i64(size)
return
}
reader_unread_rune :: proc(r: ^Reader) -> io.Error {
if r.i <= 0 {
return .Invalid_Unread;
return .Invalid_Unread
}
if r.prev_rune < 0 {
return .Invalid_Unread;
return .Invalid_Unread
}
r.i = i64(r.prev_rune);
r.prev_rune = -1;
return nil;
r.i = i64(r.prev_rune)
r.prev_rune = -1
return nil
}
reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
r.prev_rune = -1;
abs: i64;
r.prev_rune = -1
abs: i64
switch whence {
case .Start:
abs = offset;
abs = offset
case .Current:
abs = r.i + offset;
abs = r.i + offset
case .End:
abs = i64(len(r.s)) + offset;
abs = i64(len(r.s)) + offset
case:
return 0, .Invalid_Whence;
return 0, .Invalid_Whence
}
if abs < 0 {
return 0, .Invalid_Offset;
return 0, .Invalid_Offset
}
r.i = abs;
return abs, nil;
r.i = abs
return abs, nil
}
reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
r.prev_rune = -1;
r.prev_rune = -1
if r.i >= i64(len(r.s)) {
return 0, nil;
return 0, nil
}
s := r.s[r.i:];
m: int;
m, err = io.write(w, s);
s := r.s[r.i:]
m: int
m, err = io.write(w, s)
if m > len(s) {
panic("bytes.Reader.write_to: invalid io.write_string count");
panic("bytes.Reader.write_to: invalid io.write_string count")
}
r.i += i64(m);
n = i64(m);
r.i += i64(m)
n = i64(m)
if m != len(s) && err == nil {
err = .Short_Write;
err = .Short_Write
}
return;
return
}
@(private)
_reader_vtable := &io.Stream_VTable{
impl_size = proc(s: io.Stream) -> i64 {
r := (^Reader)(s.stream_data);
return reader_size(r);
r := (^Reader)(s.stream_data)
return reader_size(r)
},
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
r := (^Reader)(s.stream_data);
return reader_read(r, p);
r := (^Reader)(s.stream_data)
return reader_read(r, p)
},
impl_read_at = proc(s: io.Stream, p: []byte, off: i64) -> (n: int, err: io.Error) {
r := (^Reader)(s.stream_data);
return reader_read_at(r, p, off);
r := (^Reader)(s.stream_data)
return reader_read_at(r, p, off)
},
impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) {
r := (^Reader)(s.stream_data);
return reader_read_byte(r);
r := (^Reader)(s.stream_data)
return reader_read_byte(r)
},
impl_unread_byte = proc(s: io.Stream) -> io.Error {
r := (^Reader)(s.stream_data);
return reader_unread_byte(r);
r := (^Reader)(s.stream_data)
return reader_unread_byte(r)
},
impl_read_rune = proc(s: io.Stream) -> (ch: rune, size: int, err: io.Error) {
r := (^Reader)(s.stream_data);
return reader_read_rune(r);
r := (^Reader)(s.stream_data)
return reader_read_rune(r)
},
impl_unread_rune = proc(s: io.Stream) -> io.Error {
r := (^Reader)(s.stream_data);
return reader_unread_rune(r);
r := (^Reader)(s.stream_data)
return reader_unread_rune(r)
},
impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
r := (^Reader)(s.stream_data);
return reader_seek(r, offset, whence);
r := (^Reader)(s.stream_data)
return reader_seek(r, offset, whence)
},
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
r := (^Reader)(s.stream_data);
return reader_write_to(r, w);
r := (^Reader)(s.stream_data)
return reader_write_to(r, w)
},
};
}
+97 -26
View File
@@ -1,35 +1,106 @@
package c
import b "core:builtin"
import builtin "core:builtin"
CHAR_BIT :: 8;
char :: builtin.u8 // assuming -funsigned-char
bool :: b.bool;
char :: b.u8;
byte :: b.byte;
schar :: b.i8;
uchar :: b.u8;
short :: b.i16;
ushort :: b.u16;
int :: b.i32;
uint :: b.u32;
schar :: builtin.i8
short :: builtin.i16
int :: builtin.i32
long :: builtin.i32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.i64
longlong :: builtin.i64
long :: b.i32 when (ODIN_OS == "windows" || size_of(b.rawptr) == 4) else b.i64;
ulong :: b.u32 when (ODIN_OS == "windows" || size_of(b.rawptr) == 4) else b.u64;
uchar :: builtin.u8
ushort :: builtin.u16
uint :: builtin.u32
ulong :: builtin.u32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.u64
ulonglong :: builtin.u64
longlong :: b.i64;
ulonglong :: b.u64;
float :: b.f32;
double :: b.f64;
complex_float :: b.complex64;
complex_double :: b.complex128;
bool :: builtin.bool
#assert(size_of(b.uintptr) == size_of(b.int));
size_t :: builtin.uint
ssize_t :: builtin.int
wchar_t :: builtin.u16 when (ODIN_OS == .Windows) else builtin.u32
size_t :: b.uint;
ssize_t :: b.int;
ptrdiff_t :: b.int;
uintptr_t :: b.uintptr;
intptr_t :: b.int;
float :: builtin.f32
double :: builtin.f64
complex_float :: builtin.complex64
complex_double :: builtin.complex128
wchar_t :: b.u16 when (ODIN_OS == "windows") else b.u32;
// 7.20.1 Integer types
int8_t :: builtin.i8
uint8_t :: builtin.u8
int16_t :: builtin.i16
uint16_t :: builtin.u16
int32_t :: builtin.i32
uint32_t :: builtin.u32
int64_t :: builtin.i64
uint64_t :: builtin.u64
// These are all the same in multiple libc's for multiple architectures.
int_least8_t :: builtin.i8
uint_least8_t :: builtin.u8
int_least16_t :: builtin.i16
uint_least16_t :: builtin.u16
int_least32_t :: builtin.i32
uint_least32_t :: builtin.u32
int_least64_t :: builtin.i64
uint_least64_t :: builtin.u64
// Same on Windows, Linux, and FreeBSD
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
int_fast8_t :: builtin.i8
uint_fast8_t :: builtin.u8
int_fast16_t :: builtin.i32
uint_fast16_t :: builtin.u32
int_fast32_t :: builtin.i32
uint_fast32_t :: builtin.u32
int_fast64_t :: builtin.i64
uint_fast64_t :: builtin.u64
} else {
int_fast8_t :: builtin.i8
uint_fast8_t :: builtin.u8
int_fast16_t :: builtin.i16
uint_fast16_t :: builtin.u16
int_fast32_t :: builtin.i32
uint_fast32_t :: builtin.u32
int_fast64_t :: builtin.i64
uint_fast64_t :: builtin.u64
}
intptr_t :: builtin.int
uintptr_t :: builtin.uintptr
ptrdiff_t :: distinct intptr_t
intmax_t :: builtin.i64
uintmax_t :: builtin.u64
// Copy C's rules for type promotion here by forcing the type on the literals.
INT8_MAX :: int(0x7f)
INT16_MAX :: int(0x7fff)
INT32_MAX :: int(0x7fffffff)
INT64_MAX :: longlong(0x7fffffffffffffff)
UINT8_MAX :: int(0xff)
UINT16_MAX :: int(0xffff)
UINT32_MAX :: uint(0xffffffff)
UINT64_MAX :: ulonglong(0xffffffffffffffff)
INT8_MIN :: ~INT8_MAX
INT16_MIN :: ~INT16_MAX
INT32_MIN :: ~INT32_MAX
INT64_MIN :: ~INT64_MAX
SIZE_MAX :: max(size_t)
PTRDIFF_MIN :: min(ptrdiff_t)
PTRDIFF_MAX :: max(ptrdiff_t)
WCHAR_MIN :: min(wchar_t)
WCHAR_MAX :: max(wchar_t)
NULL :: rawptr(uintptr(0))
NDEBUG :: !ODIN_DEBUG
CHAR_BIT :: 8
+7 -7
View File
@@ -6,20 +6,20 @@ const_expr :: proc(rest: ^^Token, tok: ^Token) -> i64 {
// TODO(bill): Handle const_expr correctly
// This is effectively a mini-parser
assert(rest != nil);
assert(tok != nil);
rest^ = tokenizer.new_eof(tok);
assert(rest != nil)
assert(tok != nil)
rest^ = tokenizer.new_eof(tok)
switch v in tok.val {
case i64:
return v;
return v
case f64:
return i64(v);
return i64(v)
case string:
return 0;
return 0
case []u16:
// TODO
case []u32:
// TODO
}
return 0;
return 0
}
File diff suppressed because it is too large Load Diff
+72 -72
View File
@@ -5,150 +5,150 @@ import "core:unicode/utf8"
unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
hex_to_int :: proc(c: byte) -> int {
switch c {
case '0'..'9': return int(c-'0');
case 'a'..'f': return int(c-'a')+10;
case 'A'..'F': return int(c-'A')+10;
case '0'..='9': return int(c-'0')
case 'a'..='f': return int(c-'a')+10
case 'A'..='F': return int(c-'A')+10
}
return -1;
return -1
}
w: int;
w: int
if str[0] == quote && quote == '"' {
return;
return
} else if str[0] >= 0x80 {
r, w = utf8.decode_rune_in_string(str);
return r, true, str[w:], true;
r, w = utf8.decode_rune_in_string(str)
return r, true, str[w:], true
} else if str[0] != '\\' {
return rune(str[0]), false, str[1:], true;
return rune(str[0]), false, str[1:], true
}
if len(str) <= 1 {
return;
return
}
s := str;
c := s[1];
s = s[2:];
s := str
c := s[1]
s = s[2:]
switch c {
case: r = rune(c);
case: r = rune(c)
case 'a': r = '\a';
case 'b': r = '\b';
case 'e': r = '\e';
case 'f': r = '\f';
case 'n': r = '\n';
case 'r': r = '\r';
case 't': r = '\t';
case 'v': r = '\v';
case '\\': r = '\\';
case 'a': r = '\a'
case 'b': r = '\b'
case 'e': r = '\e'
case 'f': r = '\f'
case 'n': r = '\n'
case 'r': r = '\r'
case 't': r = '\t'
case 'v': r = '\v'
case '\\': r = '\\'
case '"': r = '"';
case '\'': r = '\'';
case '"': r = '"'
case '\'': r = '\''
case '0'..'7':
v := int(c-'0');
case '0'..='7':
v := int(c-'0')
if len(s) < 2 {
return;
return
}
for i in 0..<len(s) {
d := int(s[i]-'0');
d := int(s[i]-'0')
if d < 0 || d > 7 {
return;
return
}
v = (v<<3) | d;
v = (v<<3) | d
}
s = s[2:];
s = s[2:]
if v > 0xff {
return;
return
}
r = rune(v);
r = rune(v)
case 'x', 'u', 'U':
count: int;
count: int
switch c {
case 'x': count = 2;
case 'u': count = 4;
case 'U': count = 8;
case 'x': count = 2
case 'u': count = 4
case 'U': count = 8
}
if len(s) < count {
return;
return
}
for i in 0..<count {
d := hex_to_int(s[i]);
d := hex_to_int(s[i])
if d < 0 {
return;
return
}
r = (r<<4) | rune(d);
r = (r<<4) | rune(d)
}
s = s[count:];
s = s[count:]
if c == 'x' {
break;
break
}
if r > utf8.MAX_RUNE {
return;
return
}
multiple_bytes = true;
multiple_bytes = true
}
success = true;
tail_string = s;
return;
success = true
tail_string = s
return
}
unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: string, allocated, success: bool) {
contains_rune :: proc(s: string, r: rune) -> int {
for c, offset in s {
if c == r {
return offset;
return offset
}
}
return -1;
return -1
}
assert(len(lit) >= 2);
assert(len(lit) >= 2)
s := lit;
quote := '"';
s := lit
quote := '"'
if s == `""` {
return "", false, true;
return "", false, true
}
if contains_rune(s, '\n') >= 0 {
return s, false, false;
return s, false, false
}
if contains_rune(s, '\\') < 0 && contains_rune(s, quote) < 0 {
if quote == '"' {
return s, false, true;
return s, false, true
}
}
s = s[1:len(s)-1];
s = s[1:len(s)-1]
buf_len := 3*len(s) / 2;
buf := make([]byte, buf_len, allocator);
offset := 0;
buf_len := 3*len(s) / 2
buf := make([]byte, buf_len, allocator)
offset := 0
for len(s) > 0 {
r, multiple_bytes, tail_string, ok := unquote_char(s, byte(quote));
r, multiple_bytes, tail_string, ok := unquote_char(s, byte(quote))
if !ok {
delete(buf);
return s, false, false;
delete(buf)
return s, false, false
}
s = tail_string;
s = tail_string
if r < 0x80 || !multiple_bytes {
buf[offset] = byte(r);
offset += 1;
buf[offset] = byte(r)
offset += 1
} else {
b, w := utf8.encode_rune(r);
copy(buf[offset:], b[:w]);
offset += w;
b, w := utf8.encode_rune(r)
copy(buf[offset:], b[:w])
offset += w
}
}
new_string := string(buf[:offset]);
new_string := string(buf[:offset])
return new_string, true, true;
return new_string, true, true
}
+24 -24
View File
@@ -11,58 +11,58 @@ Hide_Set :: struct {
new_hide_set :: proc(name: string) -> ^Hide_Set {
hs := new(Hide_Set);
hs.name = name;
return hs;
hs := new(Hide_Set)
hs.name = name
return hs
}
hide_set_contains :: proc(hs: ^Hide_Set, name: string) -> bool {
for h := hs; h != nil; h = h.next {
if h.name == name {
return true;
return true
}
}
return false;
return false
}
hide_set_union :: proc(a, b: ^Hide_Set) -> ^Hide_Set {
head: Hide_Set;
curr := &head;
head: Hide_Set
curr := &head
for h := a; h != nil; h = h.next {
curr.next = new_hide_set(h.name);
curr = curr.next;
curr.next = new_hide_set(h.name)
curr = curr.next
}
curr.next = b;
return head.next;
curr.next = b
return head.next
}
hide_set_intersection :: proc(a, b: ^Hide_Set) -> ^Hide_Set {
head: Hide_Set;
curr := &head;
head: Hide_Set
curr := &head
for h := a; h != nil; h = h.next {
if hide_set_contains(b, h.name) {
curr.next = new_hide_set(h.name);
curr = curr.next;
curr.next = new_hide_set(h.name)
curr = curr.next
}
}
return head.next;
return head.next
}
add_hide_set :: proc(tok: ^Token, hs: ^Hide_Set) -> ^Token {
head: Token;
curr := &head;
head: Token
curr := &head
tok := tok;
tok := tok
for ; tok != nil; tok = tok.next {
t := copy_token(tok);
t.hide_set = hide_set_union(t.hide_set, hs);
curr.next = t;
curr = curr.next;
t := copy_token(tok)
t.hide_set = hide_set_union(t.hide_set, hs)
curr.next = t
curr = curr.next
}
return head.next;
return head.next
}
+13 -13
View File
@@ -80,29 +80,29 @@ Token :: struct {
origin: ^Token,
}
Is_Keyword_Proc :: #type proc(tok: ^Token) -> bool;
Is_Keyword_Proc :: #type proc(tok: ^Token) -> bool
copy_token :: proc(tok: ^Token) -> ^Token {
t := new_clone(tok^);
t.next = nil;
return t;
t, _ := new_clone(tok^)
t.next = nil
return t
}
new_eof :: proc(tok: ^Token) -> ^Token {
t := new_clone(tok^);
t.kind = .EOF;
t.lit = "";
return t;
t, _ := new_clone(tok^)
t.kind = .EOF
t.lit = ""
return t
}
default_is_keyword :: proc(tok: ^Token) -> bool {
if tok.kind == .Keyword {
return true;
return true
}
if len(tok.lit) > 0 {
return default_keyword_set[tok.lit];
return default_keyword_set[tok.lit]
}
return false;
return false
}
@@ -117,7 +117,7 @@ token_name := [Token_Kind]string {
.PP_Number = "preprocessor number",
.Comment = "comment",
.EOF = "eof",
};
}
default_keyword_set := map[string]bool{
"auto" = true,
@@ -166,4 +166,4 @@ default_keyword_set := map[string]bool{
"__restrict__" = true,
"__thread" = true,
"__attribute__" = true,
};
}
+271 -271
View File
@@ -6,7 +6,7 @@ import "core:strings"
import "core:unicode/utf8"
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any)
Tokenizer :: struct {
@@ -34,415 +34,415 @@ Tokenizer :: struct {
}
init_defaults :: proc(t: ^Tokenizer, err: Error_Handler = default_error_handler, warn: Error_Handler = default_warn_handler) {
t.err = err;
t.warn = warn;
t.err = err
t.warn = warn
}
@(private)
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> (pos: Pos) {
pos.file = t.path;
pos.offset = offset;
pos.line = t.line_count;
pos.column = offset - t.line_offset + 1;
return;
pos.file = t.path
pos.offset = offset
pos.line = t.line_count
pos.column = offset - t.line_offset + 1
return
}
default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
fmt.eprintf(msg, ..args);
fmt.eprintf("\n");
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column)
fmt.eprintf(msg, ..args)
fmt.eprintf("\n")
}
default_warn_handler :: proc(pos: Pos, msg: string, args: ..any) {
fmt.eprintf("%s(%d:%d) warning: ", pos.file, pos.line, pos.column);
fmt.eprintf(msg, ..args);
fmt.eprintf("\n");
fmt.eprintf("%s(%d:%d) warning: ", pos.file, pos.line, pos.column)
fmt.eprintf(msg, ..args)
fmt.eprintf("\n")
}
error_offset :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
pos := offset_to_pos(t, offset);
pos := offset_to_pos(t, offset)
if t.err != nil {
t.err(pos, msg, ..args);
t.err(pos, msg, ..args)
}
t.error_count += 1;
t.error_count += 1
}
warn_offset :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
pos := offset_to_pos(t, offset);
pos := offset_to_pos(t, offset)
if t.warn != nil {
t.warn(pos, msg, ..args);
t.warn(pos, msg, ..args)
}
t.warning_count += 1;
t.warning_count += 1
}
error :: proc(t: ^Tokenizer, tok: ^Token, msg: string, args: ..any) {
pos := tok.pos;
pos := tok.pos
if t.err != nil {
t.err(pos, msg, ..args);
t.err(pos, msg, ..args)
}
t.error_count += 1;
t.error_count += 1
}
warn :: proc(t: ^Tokenizer, tok: ^Token, msg: string, args: ..any) {
pos := tok.pos;
pos := tok.pos
if t.warn != nil {
t.warn(pos, msg, ..args);
t.warn(pos, msg, ..args)
}
t.warning_count += 1;
t.warning_count += 1
}
advance_rune :: proc(t: ^Tokenizer) {
if t.read_offset < len(t.src) {
t.offset = t.read_offset;
t.offset = t.read_offset
if t.ch == '\n' {
t.at_bol = true;
t.line_offset = t.offset;
t.line_count += 1;
t.at_bol = true
t.line_offset = t.offset
t.line_count += 1
}
r, w := rune(t.src[t.read_offset]), 1;
r, w := rune(t.src[t.read_offset]), 1
switch {
case r == 0:
error_offset(t, t.offset, "illegal character NUL");
error_offset(t, t.offset, "illegal character NUL")
case r >= utf8.RUNE_SELF:
r, w = utf8.decode_rune(t.src[t.read_offset:]);
r, w = utf8.decode_rune(t.src[t.read_offset:])
if r == utf8.RUNE_ERROR && w == 1 {
error_offset(t, t.offset, "illegal UTF-8 encoding");
error_offset(t, t.offset, "illegal UTF-8 encoding")
} else if r == utf8.RUNE_BOM && t.offset > 0 {
error_offset(t, t.offset, "illegal byte order mark");
error_offset(t, t.offset, "illegal byte order mark")
}
}
t.read_offset += w;
t.ch = r;
t.read_offset += w
t.ch = r
} else {
t.offset = len(t.src);
t.offset = len(t.src)
if t.ch == '\n' {
t.at_bol = true;
t.line_offset = t.offset;
t.line_count += 1;
t.at_bol = true
t.line_offset = t.offset
t.line_count += 1
}
t.ch = -1;
t.ch = -1
}
}
advance_rune_n :: proc(t: ^Tokenizer, n: int) {
for in 0..<n {
advance_rune(t);
advance_rune(t)
}
}
is_digit :: proc(r: rune) -> bool {
return '0' <= r && r <= '9';
return '0' <= r && r <= '9'
}
skip_whitespace :: proc(t: ^Tokenizer) {
for {
switch t.ch {
case ' ', '\t', '\r', '\v', '\f', '\n':
t.has_space = true;
advance_rune(t);
t.has_space = true
advance_rune(t)
case:
return;
return
}
}
}
scan_comment :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
next := -1;
offset := t.offset-1
next := -1
general: {
if t.ch == '/'{ // line comments
advance_rune(t);
advance_rune(t)
for t.ch != '\n' && t.ch >= 0 {
advance_rune(t);
advance_rune(t)
}
next = t.offset;
next = t.offset
if t.ch == '\n' {
next += 1;
next += 1
}
break general;
break general
}
/* style comment */
advance_rune(t);
advance_rune(t)
for t.ch >= 0 {
ch := t.ch;
advance_rune(t);
ch := t.ch
advance_rune(t)
if ch == '*' && t.ch == '/' {
advance_rune(t);
next = t.offset;
break general;
advance_rune(t)
next = t.offset
break general
}
}
error_offset(t, offset, "comment not terminated");
error_offset(t, offset, "comment not terminated")
}
lit := t.src[offset : t.offset];
lit := t.src[offset : t.offset]
// NOTE(bill): Strip CR for line comments
for len(lit) > 2 && lit[1] == '/' && lit[len(lit)-1] == '\r' {
lit = lit[:len(lit)-1];
lit = lit[:len(lit)-1]
}
return string(lit);
return string(lit)
}
scan_identifier :: proc(t: ^Tokenizer) -> string {
offset := t.offset;
offset := t.offset
for is_ident1(t.ch) {
advance_rune(t);
advance_rune(t)
}
return string(t.src[offset : t.offset]);
return string(t.src[offset : t.offset])
}
scan_string :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
offset := t.offset-1
for {
ch := t.ch;
ch := t.ch
if ch == '\n' || ch < 0 {
error_offset(t, offset, "string literal was not terminated");
break;
error_offset(t, offset, "string literal was not terminated")
break
}
advance_rune(t);
advance_rune(t)
if ch == '"' {
break;
break
}
if ch == '\\' {
scan_escape(t);
scan_escape(t)
}
}
return string(t.src[offset : t.offset]);
return string(t.src[offset : t.offset])
}
digit_val :: proc(r: rune) -> int {
switch r {
case '0'..'9':
return int(r-'0');
case 'A'..'F':
return int(r-'A' + 10);
case 'a'..'f':
return int(r-'a' + 10);
case '0'..='9':
return int(r-'0')
case 'A'..='F':
return int(r-'A' + 10)
case 'a'..='f':
return int(r-'a' + 10)
}
return 16;
return 16
}
scan_escape :: proc(t: ^Tokenizer) -> bool {
offset := t.offset;
offset := t.offset
esc := t.ch;
n: int;
base, max: u32;
esc := t.ch
n: int
base, max: u32
switch esc {
case 'a', 'b', 'e', 'f', 'n', 't', 'v', 'r', '\\', '\'', '"':
advance_rune(t);
return true;
advance_rune(t)
return true
case '0'..'7':
case '0'..='7':
for digit_val(t.ch) < 8 {
advance_rune(t);
advance_rune(t)
}
return true;
return true
case 'x':
advance_rune(t);
advance_rune(t)
for digit_val(t.ch) < 16 {
advance_rune(t);
advance_rune(t)
}
return true;
return true
case 'u':
advance_rune(t);
n, base, max = 4, 16, utf8.MAX_RUNE;
advance_rune(t)
n, base, max = 4, 16, utf8.MAX_RUNE
case 'U':
advance_rune(t);
n, base, max = 8, 16, utf8.MAX_RUNE;
advance_rune(t)
n, base, max = 8, 16, utf8.MAX_RUNE
case:
if t.ch < 0 {
error_offset(t, offset, "escape sequence was not terminated");
error_offset(t, offset, "escape sequence was not terminated")
} else {
break;
break
}
return false;
return false
}
x: u32;
x: u32
main_loop: for n > 0 {
d := u32(digit_val(t.ch));
d := u32(digit_val(t.ch))
if d >= base {
if t.ch == '"' || t.ch == '\'' {
break main_loop;
break main_loop
}
if t.ch < 0 {
error_offset(t, t.offset, "escape sequence was not terminated");
error_offset(t, t.offset, "escape sequence was not terminated")
} else {
error_offset(t, t.offset, "illegal character '%r' : %d in escape sequence", t.ch, t.ch);
error_offset(t, t.offset, "illegal character '%r' : %d in escape sequence", t.ch, t.ch)
}
return false;
return false
}
x = x*base + d;
advance_rune(t);
n -= 1;
x = x*base + d
advance_rune(t)
n -= 1
}
if x > max || 0xd800 <= x && x <= 0xe000 {
error_offset(t, offset, "escape sequence is an invalid Unicode code point");
return false;
error_offset(t, offset, "escape sequence is an invalid Unicode code point")
return false
}
return true;
return true
}
scan_rune :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
valid := true;
n := 0;
offset := t.offset-1
valid := true
n := 0
for {
ch := t.ch;
ch := t.ch
if ch == '\n' || ch < 0 {
if valid {
error_offset(t, offset, "rune literal not terminated");
valid = false;
error_offset(t, offset, "rune literal not terminated")
valid = false
}
break;
break
}
advance_rune(t);
advance_rune(t)
if ch == '\'' {
break;
break
}
n += 1;
n += 1
if ch == '\\' {
if !scan_escape(t) {
valid = false;
valid = false
}
}
}
if valid && n != 1 {
error_offset(t, offset, "illegal rune literal");
error_offset(t, offset, "illegal rune literal")
}
return string(t.src[offset : t.offset]);
return string(t.src[offset : t.offset])
}
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
for digit_val(t.ch) < base {
advance_rune(t);
advance_rune(t)
}
}
scan_exponent :: proc(t: ^Tokenizer) {
if t.ch == 'e' || t.ch == 'E' || t.ch == 'p' || t.ch == 'P' {
advance_rune(t);
advance_rune(t)
if t.ch == '-' || t.ch == '+' {
advance_rune(t);
advance_rune(t)
}
if digit_val(t.ch) < 10 {
scan_mantissa(t, 10);
scan_mantissa(t, 10)
} else {
error_offset(t, t.offset, "illegal floating-point exponent");
error_offset(t, t.offset, "illegal floating-point exponent")
}
}
}
scan_fraction :: proc(t: ^Tokenizer) -> (early_exit: bool) {
if t.ch == '.' && peek(t) == '.' {
return true;
return true
}
if t.ch == '.' {
advance_rune(t);
scan_mantissa(t, 10);
advance_rune(t)
scan_mantissa(t, 10)
}
return false;
return false
}
check_end := true;
check_end := true
offset := t.offset;
seen_point := seen_decimal_point;
offset := t.offset
seen_point := seen_decimal_point
if seen_point {
offset -= 1;
scan_mantissa(t, 10);
scan_exponent(t);
offset -= 1
scan_mantissa(t, 10)
scan_exponent(t)
} else {
if t.ch == '0' {
int_base :: proc(t: ^Tokenizer, base: int, msg: string) {
prev := t.offset;
advance_rune(t);
scan_mantissa(t, base);
prev := t.offset
advance_rune(t)
scan_mantissa(t, base)
if t.offset - prev <= 1 {
error_offset(t, t.offset, msg);
error_offset(t, t.offset, msg)
}
}
advance_rune(t);
advance_rune(t)
switch t.ch {
case 'b', 'B':
int_base(t, 2, "illegal binary integer");
int_base(t, 2, "illegal binary integer")
case 'x', 'X':
int_base(t, 16, "illegal hexadecimal integer");
int_base(t, 16, "illegal hexadecimal integer")
case:
seen_point = false;
scan_mantissa(t, 10);
seen_point = false
scan_mantissa(t, 10)
if t.ch == '.' {
seen_point = true;
seen_point = true
if scan_fraction(t) {
check_end = false;
check_end = false
}
}
if check_end {
scan_exponent(t);
check_end = false;
scan_exponent(t)
check_end = false
}
}
}
}
if check_end {
scan_mantissa(t, 10);
scan_mantissa(t, 10)
if !scan_fraction(t) {
scan_exponent(t);
scan_exponent(t)
}
}
return .Number, string(t.src[offset : t.offset]);
return .Number, string(t.src[offset : t.offset])
}
scan_punct :: proc(t: ^Tokenizer, ch: rune) -> (kind: Token_Kind) {
kind = .Punct;
kind = .Punct
switch ch {
case:
kind = .Invalid;
kind = .Invalid
case '<', '>':
if t.ch == ch {
advance_rune(t);
advance_rune(t)
}
if t.ch == '=' {
advance_rune(t);
advance_rune(t)
}
case '!', '+', '-', '*', '/', '%', '^', '=':
if t.ch == '=' {
advance_rune(t);
advance_rune(t)
}
case '#':
if t.ch == '#' {
advance_rune(t);
advance_rune(t)
}
case '&':
if t.ch == '=' || t.ch == '&' {
advance_rune(t);
advance_rune(t)
}
case '|':
if t.ch == '=' || t.ch == '|' {
advance_rune(t);
advance_rune(t)
}
case '(', ')', '[', ']', '{', '}':
// okay
@@ -452,216 +452,216 @@ scan_punct :: proc(t: ^Tokenizer, ch: rune) -> (kind: Token_Kind) {
// okay
case '.':
if t.ch == '.' && peek(t) == '.' {
advance_rune(t);
advance_rune(t); // consume last '.'
advance_rune(t)
advance_rune(t) // consume last '.'
}
}
return;
return
}
peek :: proc(t: ^Tokenizer) -> byte {
if t.read_offset < len(t.src) {
return t.src[t.read_offset];
return t.src[t.read_offset]
}
return 0;
return 0
}
peek_str :: proc(t: ^Tokenizer, str: string) -> bool {
if t.read_offset < len(t.src) {
return strings.has_prefix(string(t.src[t.offset:]), str);
return strings.has_prefix(string(t.src[t.offset:]), str)
}
return false;
return false
}
scan_literal_prefix :: proc(t: ^Tokenizer, str: string, prefix: ^string) -> bool {
if peek_str(t, str) {
offset := t.offset;
offset := t.offset
for _ in str {
advance_rune(t);
advance_rune(t)
}
prefix^ = string(t.src[offset:][:len(str)-1]);
return true;
prefix^ = string(t.src[offset:][:len(str)-1])
return true
}
return false;
return false
}
allow_next_to_be_newline :: proc(t: ^Tokenizer) -> bool {
if t.ch == '\n' {
advance_rune(t);
return true;
advance_rune(t)
return true
} else if t.ch == '\r' && peek(t) == '\n' { // allow for MS-DOS style line endings
advance_rune(t); // \r
advance_rune(t); // \n
return true;
advance_rune(t) // \r
advance_rune(t) // \n
return true
}
return false;
return false
}
scan :: proc(t: ^Tokenizer, f: ^File) -> ^Token {
skip_whitespace(t);
skip_whitespace(t)
offset := t.offset;
offset := t.offset
kind: Token_Kind;
lit: string;
prefix: string;
kind: Token_Kind
lit: string
prefix: string
switch ch := t.ch; {
case scan_literal_prefix(t, `u8"`, &prefix):
kind = .String;
lit = scan_string(t);
kind = .String
lit = scan_string(t)
case scan_literal_prefix(t, `u"`, &prefix):
kind = .String;
lit = scan_string(t);
kind = .String
lit = scan_string(t)
case scan_literal_prefix(t, `L"`, &prefix):
kind = .String;
lit = scan_string(t);
kind = .String
lit = scan_string(t)
case scan_literal_prefix(t, `U"`, &prefix):
kind = .String;
lit = scan_string(t);
kind = .String
lit = scan_string(t)
case scan_literal_prefix(t, `u'`, &prefix):
kind = .Char;
lit = scan_rune(t);
kind = .Char
lit = scan_rune(t)
case scan_literal_prefix(t, `L'`, &prefix):
kind = .Char;
lit = scan_rune(t);
kind = .Char
lit = scan_rune(t)
case scan_literal_prefix(t, `U'`, &prefix):
kind = .Char;
lit = scan_rune(t);
kind = .Char
lit = scan_rune(t)
case is_ident0(ch):
lit = scan_identifier(t);
kind = .Ident;
lit = scan_identifier(t)
kind = .Ident
case '0' <= ch && ch <= '9':
kind, lit = scan_number(t, false);
kind, lit = scan_number(t, false)
case:
advance_rune(t);
advance_rune(t)
switch ch {
case -1:
kind = .EOF;
kind = .EOF
case '\\':
kind = .Punct;
kind = .Punct
if allow_next_to_be_newline(t) {
t.at_bol = true;
t.has_space = false;
return scan(t, f);
t.at_bol = true
t.has_space = false
return scan(t, f)
}
case '.':
if is_digit(t.ch) {
kind, lit = scan_number(t, true);
kind, lit = scan_number(t, true)
} else {
kind = scan_punct(t, ch);
kind = scan_punct(t, ch)
}
case '"':
kind = .String;
lit = scan_string(t);
kind = .String
lit = scan_string(t)
case '\'':
kind = .Char;
lit = scan_rune(t);
kind = .Char
lit = scan_rune(t)
case '/':
if t.ch == '/' || t.ch == '*' {
kind = .Comment;
lit = scan_comment(t);
t.has_space = true;
break;
kind = .Comment
lit = scan_comment(t)
t.has_space = true
break
}
fallthrough;
fallthrough
case:
kind = scan_punct(t, ch);
kind = scan_punct(t, ch)
if kind == .Invalid && ch != utf8.RUNE_BOM {
error_offset(t, t.offset, "illegal character '%r': %d", ch, ch);
error_offset(t, t.offset, "illegal character '%r': %d", ch, ch)
}
}
}
if lit == "" {
lit = string(t.src[offset : t.offset]);
lit = string(t.src[offset : t.offset])
}
if kind == .Comment {
return scan(t, f);
return scan(t, f)
}
tok := new(Token);
tok.kind = kind;
tok.lit = lit;
tok.pos = offset_to_pos(t, offset);
tok.file = f;
tok.prefix = prefix;
tok.at_bol = t.at_bol;
tok.has_space = t.has_space;
tok := new(Token)
tok.kind = kind
tok.lit = lit
tok.pos = offset_to_pos(t, offset)
tok.file = f
tok.prefix = prefix
tok.at_bol = t.at_bol
tok.has_space = t.has_space
t.at_bol, t.has_space = false, false;
t.at_bol, t.has_space = false, false
return tok;
return tok
}
tokenize :: proc(t: ^Tokenizer, f: ^File) -> ^Token {
setup_tokenizer: {
t.src = f.src;
t.ch = ' ';
t.offset = 0;
t.read_offset = 0;
t.line_offset = 0;
t.line_count = len(t.src) > 0 ? 1 : 0;
t.error_count = 0;
t.path = f.name;
t.src = f.src
t.ch = ' '
t.offset = 0
t.read_offset = 0
t.line_offset = 0
t.line_count = len(t.src) > 0 ? 1 : 0
t.error_count = 0
t.path = f.name
advance_rune(t);
advance_rune(t)
if t.ch == utf8.RUNE_BOM {
advance_rune(t);
advance_rune(t)
}
}
t.at_bol = true;
t.has_space = false;
t.at_bol = true
t.has_space = false
head: Token;
curr := &head;
head: Token
curr := &head
for {
tok := scan(t, f);
tok := scan(t, f)
if tok == nil {
break;
break
}
curr.next = tok;
curr = curr.next;
curr.next = tok
curr = curr.next
if tok.kind == .EOF {
break;
break
}
}
return head.next;
return head.next
}
add_new_file :: proc(t: ^Tokenizer, name: string, src: []byte, id: int) -> ^File {
file := new(File);
file.id = id;
file.src = src;
file.name = name;
file.display_name = name;
return file;
file := new(File)
file.id = id
file.src = src
file.name = name
file.display_name = name
return file
}
tokenize_file :: proc(t: ^Tokenizer, path: string, id: int, loc := #caller_location) -> ^Token {
src, ok := os.read_entire_file(path);
src, ok := os.read_entire_file(path)
if !ok {
return nil;
return nil
}
return tokenize(t, add_new_file(t, path, src, id));
return tokenize(t, add_new_file(t, path, src, id))
}
inline_tokenize :: proc(t: ^Tokenizer, tok: ^Token, src: []byte) -> ^Token {
file := new(File);
file.src = src;
file := new(File)
file.src = src
if tok.file != nil {
file.id = tok.file.id;
file.name = tok.file.name;
file.display_name = tok.file.name;
file.id = tok.file.id
file.name = tok.file.name
file.display_name = tok.file.name
}
return tokenize(t, file);
return tokenize(t, file)
}
+13 -13
View File
@@ -4,10 +4,10 @@ package c_frontend_tokenizer
in_range :: proc(range: []rune, c: rune) -> bool #no_bounds_check {
for i := 0; range[i] != -1; i += 2 {
if range[i] <= c && c <= range[i+1] {
return true;
return true
}
}
return false;
return false
}
@@ -15,11 +15,11 @@ in_range :: proc(range: []rune, c: rune) -> bool #no_bounds_check {
//
// is_ident0 returns true if a given character is acceptable as the first character of an identifier.
is_ident0 :: proc(c: rune) -> bool {
return in_range(_range_ident0, c);
return in_range(_range_ident0, c)
}
// is_ident0 returns true if a given character is acceptable as a non-first character of an identifier.
is_ident1 :: proc(c: rune) -> bool {
return is_ident0(c) || in_range(_range_ident1, c);
return is_ident0(c) || in_range(_range_ident1, c)
}
// Returns the number of columns needed to display a given character in a fixed-width font.
@@ -27,18 +27,18 @@ is_ident1 :: proc(c: rune) -> bool {
char_width :: proc(c: rune) -> int {
switch {
case in_range(_range_width0, c):
return 0;
return 0
case in_range(_range_width2, c):
return 2;
return 2
}
return 1;
return 1
}
display_width :: proc(str: string) -> (w: int) {
for c in str {
w += char_width(c);
w += char_width(c)
}
return;
return
}
@@ -59,12 +59,12 @@ _range_ident0 := []rune{
0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD,
0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD,
-1,
};
}
_range_ident1 := []rune{
'0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F,
-1,
};
}
_range_width0 := []rune{
@@ -105,7 +105,7 @@ _range_width0 := []rune{
0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,
0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,
-1,
};
}
_range_width2 := []rune{
0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,
@@ -113,4 +113,4 @@ _range_width2 := []rune{
0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,
0x20000, 0x2FFFD, 0x30000, 0x3FFFD,
-1,
};
}
+73
View File
@@ -0,0 +1,73 @@
# C support
The following is a mostly-complete projection of the C11 standard library as defined by the C11 specification: N1570, or ISO/IEC 9899:2011. Only the macros, types, and functions as required by the standard are projected. Extensions to C, such as POSIX are not handled by these bindings, this is otherwise portable to any implementation which can support a hosted C runtime.
## Support matrix
| Header | Status |
|:------------------|:---------------------------------------------------|
| `<assert.h>` | Not applicable, use Odin's `#assert` |
| `<complex.h>` | Mostly projected, see [limitations](#Limitations) |
| `<ctype.h>` | Fully projected |
| `<errno.h>` | Fully projected |
| `<fenv.h>` | Not projected |
| `<float.h>` | Not projected |
| `<inttypes.h>` | Fully projected |
| `<iso646.h>` | Not applicable, use Odin's operators |
| `<limits.h>` | Not projected |
| `<locale.h>` | Not projected |
| `<math.h>` | Mostly projected, see [limitations](#Limitations) |
| `<setjmp.h>` | Fully projected |
| `<signal.h>` | Fully projected |
| `<stdalign.h>` | Not applicable, use Odin's `#align` |
| `<stdarg.h>` | Mostly projected, see [limitations](#Limitations) |
| `<stdatomic.h>` | Fully projected |
| `<stdbool.h>` | Not applicable, use Odin's `b32` |
| `<stddef.h>` | Mostly projected, see [limitations](#Limitations) |
| `<stdint.h>` | Fully projected |
| `<stdio.h>` | Fully projected |
| `<stdlib.h>` | Fully projected |
| `<stdnoreturn.h>` | Not applicable, use Odin's divergent return `!` |
| `<string.h>` | Fully projected |
| `<tgmath.h>` | Mostly projected, see [limitations](#Limitations) |
| `<threads.h>` | Fully projected |
| `<time.h>` | Fully projected |
| `<uchar.h>` | Fully projected |
| `<wchar.h>` | Fully projected |
| `<wctype.h>` | Fully projected |
## Limitations
Not all C standard library functionality can be fully projected due to language differences. These limitations are listed here.
### `long double`
As Odin lacks a means to interact with `long double` in it's foreign interface, this projection effort does not bind or define anything requiring `long double` which is permitted by the C standard.
### `<complex.h>`
The special values `_Complex_I`, `_Imaginary_I` and the appropriate definition of `I` cannot be realized with the same type in Odin as it would be in C. The literal `1i` is tempting to use for these definitions but the semantics differ from C and would be confusing to use.
### `<math.h>`
The classification functions, e.g: `fpclassify` are required by C to be implemented as macros, meaning no implementation would expose functions in their library we could bind. Instead, we provide native Odin implementations with functionally equivalent semantics and behavior as the C ones. Unfortunately, since classification returns unspecified constant values this may be an ABI break where the value of those constants enter and exit native C code.
### `<stdarg.h>`
While Odin can interact with variable argument C functions through the use of the `#c_vararg` attribute within a foreign block, it's not actually possible to create procedures in Odin with bodies that have the same ABI as that of variable argument C functions, as a result `va_arg` is not projected.
### `<stddef.h>`
`offsetof` is not realizable in Odin, however you can use `offset_of` instead.
### `<tgmath.h>`
C has some strange promotion and type-coercion behavior for `<tgmath.h>` which isn't correctly handled by this projection, specifically involving the use of complex arithmetic and kernels. We do mostly support type-generic math through the use of Odin's explicit procedure overloading, however the semantic behavior of that doesn't match C and so literal expressions of complex type in C may not call the same underlying math kernel functions as they do in Odin through this projection.
## Caveats
In addition to limitations, there are some minor caveats you should be aware when using this projection.
* `errno()` is a function which returns `^int` rather than a macro.
* `MB_CUR_MAX()` is a function which return `size_t` rather than a macro.
* Currently only works on Windows (MSVCRT) and Linux (GLIBC or MUSL)
## License
Every file within this directory is made available under Odin's BSD-2 license
with the following copyright.
```
Copyright 2021 Dale Weiler <weilercdale@gmail.com>.
```
+84
View File
@@ -0,0 +1,84 @@
package libc
// 7.3 Complex arithmetic
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
@(default_calling_convention="c")
foreign libc {
// 7.3.5 Trigonometric functions
cacos :: proc(z: complex_double) -> complex_double ---
cacosf :: proc(z: complex_float) -> complex_float ---
casin :: proc(z: complex_double) -> complex_double ---
casinf :: proc(z: complex_float) -> complex_float ---
catan :: proc(z: complex_double) -> complex_double ---
catanf :: proc(z: complex_float) -> complex_float ---
ccos :: proc(z: complex_double) -> complex_double ---
ccosf :: proc(z: complex_float) -> complex_float ---
csin :: proc(z: complex_double) -> complex_double ---
csinf :: proc(z: complex_float) -> complex_float ---
ctan :: proc(z: complex_double) -> complex_double ---
ctanf :: proc(z: complex_float) -> complex_float ---
// 7.3.6 Hyperbolic functions
cacosh :: proc(z: complex_double) -> complex_double ---
cacoshf :: proc(z: complex_float) -> complex_float ---
casinh :: proc(z: complex_double) -> complex_double ---
casinhf :: proc(z: complex_float) -> complex_float ---
catanh :: proc(z: complex_double) -> complex_double ---
catanhf :: proc(z: complex_float) -> complex_float ---
ccosh :: proc(z: complex_double) -> complex_double ---
ccoshf :: proc(z: complex_float) -> complex_float ---
csinh :: proc(z: complex_double) -> complex_double ---
csinhf :: proc(z: complex_float) -> complex_float ---
ctanh :: proc(z: complex_double) -> complex_double ---
ctanhf :: proc(z: complex_float) -> complex_float ---
// 7.3.7 Exponential and logarithmic functions
cexp :: proc(z: complex_double) -> complex_double ---
cexpf :: proc(z: complex_float) -> complex_float ---
clog :: proc(z: complex_double) -> complex_double ---
clogf :: proc(z: complex_float) -> complex_float ---
// 7.3.8 Power and absolute-value functions
cabs :: proc(z: complex_double) -> complex_double ---
cabsf :: proc(z: complex_float) -> complex_float ---
cpow :: proc(z: complex_double) -> complex_double ---
cpowf :: proc(z: complex_float) -> complex_float ---
csqrt :: proc(z: complex_double) -> complex_double ---
csqrtf :: proc(z: complex_float) -> complex_float ---
// 7.3.9 Manipulation functions
carg :: proc(z: complex_double) -> double ---
cargf :: proc(z: complex_float) -> float ---
cimag :: proc(z: complex_double) -> double ---
cimagf :: proc(z: complex_float) -> float ---
conj :: proc(z: complex_double) -> complex_double ---
conjf :: proc(z: complex_float) -> complex_float ---
cproj :: proc(z: complex_double) -> complex_double ---
cprojf :: proc(z: complex_float) -> complex_float ---
creal :: proc(z: complex_double) -> double ---
crealf :: proc(z: complex_float) -> float ---
}
import builtin "core:builtin"
complex_float :: distinct builtin.complex64
complex_double :: distinct builtin.complex128
// Cannot implement _Complex_I or _Imaginary_I in Odin, thus
// complex and imaginary cannot be implement either.
CMPLX :: #force_inline proc(x, y: double) -> complex_double {
return builtin.complex(x, y)
}
CMPLXF :: #force_inline proc(x, y: float) -> complex_float {
return builtin.complex(x, y)
}
+32
View File
@@ -0,0 +1,32 @@
package libc
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
// 7.4 Character handling
@(default_calling_convention="c")
foreign libc {
// 7.4.1 Character classification functions
isalnum :: proc(c: int) -> int ---
isalpha :: proc(c: int) -> int ---
isblank :: proc(c: int) -> int ---
iscntrl :: proc(c: int) -> int ---
isdigit :: proc(c: int) -> int ---
isgraph :: proc(c: int) -> int ---
islower :: proc(c: int) -> int ---
isprint :: proc(c: int) -> int ---
ispunct :: proc(c: int) -> int ---
isspace :: proc(c: int) -> int ---
isupper :: proc(c: int) -> int ---
isxdigit :: proc(c: int) -> int ---
// 7.4.2 Character case mapping functions
tolower :: proc(c: int) -> int ---
toupper :: proc(c: int) -> int ---
}
+76
View File
@@ -0,0 +1,76 @@
package libc
// 7.5 Errors
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
// C11 standard only requires the definition of:
// EDOM,
// EILSEQ
// ERANGE
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="__libc_errno_location")
_get_errno :: proc() -> ^int ---
}
EDOM :: 33
EILSEQ :: 84
ERANGE :: 34
}
when ODIN_OS == .OpenBSD {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="__errno")
_get_errno :: proc() -> ^int ---
}
EDOM :: 33
EILSEQ :: 84
ERANGE :: 34
}
when ODIN_OS == .Windows {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="_errno")
_get_errno :: proc() -> ^int ---
}
EDOM :: 33
EILSEQ :: 42
ERANGE :: 34
}
when ODIN_OS == .Darwin {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="__error")
_get_errno :: proc() -> ^int ---
}
// Unknown
EDOM :: 33
EILSEQ :: 92
ERANGE :: 34
}
// Odin has no way to make an identifier "errno" behave as a function call to
// read the value, or to produce an lvalue such that you can assign a different
// error value to errno. To work around this, just expose it as a function like
// it actually is.
errno :: #force_inline proc() -> ^int {
return _get_errno()
}
+404
View File
@@ -0,0 +1,404 @@
package libc
// 7.12 Mathematics
import "core:intrinsics"
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
// To support C's tgmath behavior we use Odin's explicit procedure overloading,
// but we cannot use the same names as exported by libc so use @(link_name)
// and keep them as private symbols of name "libc_"
@(private="file")
@(default_calling_convention="c")
foreign libc {
// 7.12.4 Trigonometric functions
@(link_name="acos") libc_acos :: proc(x: double) -> double ---
@(link_name="acosf") libc_acosf :: proc(x: float) -> float ---
@(link_name="asin") libc_asin :: proc(x: double) -> double ---
@(link_name="asinf") libc_asinf :: proc(x: float) -> float ---
@(link_name="atan") libc_atan :: proc(x: double) -> double ---
@(link_name="atanf") libc_atanf :: proc(x: float) -> float ---
@(link_name="atan2") libc_atan2 :: proc(y: double, x: double) -> double ---
@(link_name="atan2f") libc_atan2f :: proc(y: float, x: float) -> float ---
@(link_name="cos") libc_cos :: proc(x: double) -> double ---
@(link_name="cosf") libc_cosf :: proc(x: float) -> float ---
@(link_name="sin") libc_sin :: proc(x: double) -> double ---
@(link_name="sinf") libc_sinf :: proc(x: float) -> float ---
@(link_name="tan") libc_tan :: proc(x: double) -> double ---
@(link_name="tanf") libc_tanf :: proc(x: float) -> float ---
// 7.12.5 Hyperbolic functions
@(link_name="acosh") libc_acosh :: proc(x: double) -> double ---
@(link_name="acoshf") libc_acoshf :: proc(x: float) -> float ---
@(link_name="asinh") libc_asinh :: proc(x: double) -> double ---
@(link_name="asinhf") libc_asinhf :: proc(x: float) -> float ---
@(link_name="atanh") libc_atanh :: proc(x: double) -> double ---
@(link_name="atanhf") libc_atanhf :: proc(x: float) -> float ---
@(link_name="cosh") libc_cosh :: proc(x: double) -> double ---
@(link_name="coshf") libc_coshf :: proc(x: float) -> float ---
@(link_name="sinh") libc_sinh :: proc(x: double) -> double ---
@(link_name="sinhf") libc_sinhf :: proc(x: float) -> float ---
@(link_name="tanh") libc_tanh :: proc(x: double) -> double ---
@(link_name="tanhf") libc_tanhf :: proc(x: float) -> float ---
// 7.12.6 Exponential and logarithmic functions
@(link_name="exp") libc_exp :: proc(x: double) -> double ---
@(link_name="expf") libc_expf :: proc(x: float) -> float ---
@(link_name="exp2") libc_exp2 :: proc(x: double) -> double ---
@(link_name="exp2f") libc_exp2f :: proc(x: float) -> float ---
@(link_name="expm1") libc_expm1 :: proc(x: double) -> double ---
@(link_name="expm1f") libc_expm1f :: proc(x: float) -> float ---
@(link_name="frexp") libc_frexp :: proc(value: double, exp: ^int) -> double ---
@(link_name="frexpf") libc_frexpf :: proc(value: float, exp: ^int) -> float ---
@(link_name="ilogb") libc_ilogb :: proc(x: double) -> int ---
@(link_name="ilogbf") libc_ilogbf :: proc(x: float) -> int ---
@(link_name="ldexp") libc_ldexp :: proc(x: double, exp: int) -> double ---
@(link_name="ldexpf") libc_ldexpf :: proc(x: float, exp: int) -> float ---
@(link_name="log") libc_log :: proc(x: double) -> double ---
@(link_name="logf") libc_logf :: proc(x: float) -> float ---
@(link_name="log10") libc_log10 :: proc(x: double) -> double ---
@(link_name="log10f") libc_log10f :: proc(x: float) -> float ---
@(link_name="log1p") libc_log1p :: proc(x: double) -> double ---
@(link_name="log1pf") libc_log1pf :: proc(x: float) -> float ---
@(link_name="log2") libc_log2 :: proc(x: double) -> double ---
@(link_name="log2f") libc_log2f :: proc(x: float) -> float ---
@(link_name="logb") libc_logb :: proc(x: double) -> double ---
@(link_name="logbf") libc_logbf :: proc(x: float) -> float ---
@(link_name="modf") libc_modf :: proc(value: double, iptr: ^double) -> double ---
@(link_name="modff") libc_modff :: proc(value: float, iptr: ^float) -> float ---
@(link_name="scalbn") libc_scalbn :: proc(x: double, n: int) -> double ---
@(link_name="scalbnf") libc_scalbnf :: proc(x: float, n: int) -> float ---
@(link_name="scalbln") libc_scalbln :: proc(x: double, n: long) -> double ---
@(link_name="scalblnf") libc_scalblnf :: proc(x: float, n: long) -> float ---
// 7.12.7 Power and absolute-value functions
@(link_name="cbrt") libc_cbrt :: proc(x: double) -> double ---
@(link_name="cbrtf") libc_cbrtf :: proc(x: float) -> float ---
@(link_name="fabs") libc_fabs :: proc(x: double) -> double ---
@(link_name="fabsf") libc_fabsf :: proc(x: float) -> float ---
@(link_name="hypot") libc_hypot :: proc(x: double, y: double) -> double ---
@(link_name="hypotf") libc_hypotf :: proc(x: float, y: float) -> float ---
@(link_name="pow") libc_pow :: proc(x: double, y: double) -> double ---
@(link_name="powf") libc_powf :: proc(x: float, y: float) -> float ---
@(link_name="sqrt") libc_sqrt :: proc(x: double) -> double ---
@(link_name="sqrtf") libc_sqrtf :: proc(x: float) -> float ---
// 7.12.8 Error and gamma functions
@(link_name="erf") libc_erf :: proc(x: double) -> double ---
@(link_name="erff") libc_erff :: proc(x: float) -> float ---
@(link_name="erfc") libc_erfc :: proc(x: double) -> double ---
@(link_name="erfcf") libc_erfcf :: proc(x: float) -> float ---
@(link_name="lgamma") libc_lgamma :: proc(x: double) -> double ---
@(link_name="lgammaf") libc_lgammaf :: proc(x: float) -> float ---
@(link_name="tgamma") libc_tgamma :: proc(x: double) -> double ---
@(link_name="tgammaf") libc_tgammaf :: proc(x: float) -> float ---
// 7.12.9 Nearest integer functions
@(link_name="ceil") libc_ceil :: proc(x: double) -> double ---
@(link_name="ceilf") libc_ceilf :: proc(x: float) -> float ---
@(link_name="floor") libc_floor :: proc(x: double) -> double ---
@(link_name="floorf") libc_floorf :: proc(x: float) -> float ---
@(link_name="nearbyint") libc_nearbyint :: proc(x: double) -> double ---
@(link_name="nearbyintf") libc_nearbyintf :: proc(x: float) -> float ---
@(link_name="rint") libc_rint :: proc(x: double) -> double ---
@(link_name="rintf") libc_rintf :: proc(x: float) -> float ---
@(link_name="lrint") libc_lrint :: proc(x: double) -> long ---
@(link_name="lrintf") libc_lrintf :: proc(x: float) -> long ---
@(link_name="llrint") libc_llrint :: proc(x: double) -> longlong ---
@(link_name="llrintf") libc_llrintf :: proc(x: float) -> longlong ---
@(link_name="round") libc_round :: proc(x: double) -> double ---
@(link_name="roundf") libc_roundf :: proc(x: float) -> float ---
@(link_name="lround") libc_lround :: proc(x: double) -> long ---
@(link_name="lroundf") libc_lroundf :: proc(x: float) -> long ---
@(link_name="llround") libc_llround :: proc(x: double) -> longlong ---
@(link_name="llroundf") libc_llroundf :: proc(x: float) -> longlong ---
@(link_name="trunc") libc_trunc :: proc(x: double) -> double ---
@(link_name="truncf") libc_truncf :: proc(x: float) -> float ---
// 7.12.10 Remainder functions
@(link_name="fmod") libc_fmod :: proc(x: double, y: double) -> double ---
@(link_name="fmodf") libc_fmodf :: proc(x: float, y: float) -> float ---
@(link_name="remainder") libc_remainder :: proc(x: double, y: double) -> double ---
@(link_name="remainderf") libc_remainderf :: proc(x: float, y: float) -> float ---
@(link_name="remquo") libc_remquo :: proc(x: double, y: double, quo: ^int) -> double ---
@(link_name="remquof") libc_remquof :: proc(x: float, y: float, quo: ^int) -> float ---
// 7.12.11 Manipulation functions
@(link_name="copysign") libc_copysign :: proc(x: double, y: double) -> double ---
@(link_name="copysignf") libc_copysignf :: proc(x: float, y: float) -> float ---
@(link_name="nan") libc_nan :: proc(tagp: cstring) -> double ---
@(link_name="nanf") libc_nanf :: proc(tagp: cstring) -> float ---
@(link_name="nextafter") libc_nextafter :: proc(x: double, y: double) -> double ---
@(link_name="nextafterf") libc_nextafterf :: proc(x: float, y: float) -> float ---
// 7.12.12 Maximum, minimum, and positive difference functions
@(link_name="fdim") libc_fdim :: proc(x: double, y: double) -> double ---
@(link_name="fdimf") libc_fdimf :: proc(x: float, y: float) -> float ---
@(link_name="fmax") libc_fmax :: proc(x: double, y: double) -> double ---
@(link_name="fmaxf") libc_fmaxf :: proc(x: float, y: float) -> float ---
@(link_name="fmin") libc_fmin :: proc(x: double, y: double) -> double ---
@(link_name="fminf") libc_fminf :: proc(x: float, y: float) -> float ---
@(link_name="fma") libc_fma :: proc(x, y, z: double) -> double ---
@(link_name="fmaf") libc_fmaf :: proc(x, y, z: float) -> float ---
}
@(private="file")
_nan_bit_pattern := ~u64(0)
// On amd64 Windows and Linux, float_t and double_t are respectively both
// their usual types. On x86 it's not possible to define these types correctly
// since they would be long double which Odin does have support for.
float_t :: float
double_t :: double
NAN := transmute(double)(_nan_bit_pattern)
INFINITY :: 1e5000
HUGE_VALF :: INFINITY
HUGE_VAL :: double(INFINITY)
MATH_ERRNO :: 1
MATH_ERREXCEPT :: 2
math_errhandling :: 2 // Windows, Linux, macOS all use this mode.
FP_ILOGBNAN :: -1 - int((~uint(0)) >> 1)
FP_ILOGB0 :: FP_ILOGBNAN
// Number classification constants. These do not have to match libc since we
// implement our own classification functions as libc requires they be macros,
// which means libc does not export standard functions for them.
FP_NAN :: 0
FP_INFINITE :: 1
FP_ZERO :: 2
FP_NORMAL :: 3
FP_SUBNORMAL :: 4
@(private)
_fpclassify :: #force_inline proc(x: double) -> int {
u := transmute(uint64_t)x
switch e := u >> 52 & 0x7ff; e {
case 0: return FP_SUBNORMAL if (u << 1) != 0 else FP_ZERO
case 0x7ff: return FP_NAN if (u << 12) != 0 else FP_INFINITE
}
return FP_NORMAL
}
@(private)
_fpclassifyf :: #force_inline proc(x: float) -> int {
u := transmute(uint32_t)x
switch e := u >> 23 & 0xff; e {
case 0: return FP_SUBNORMAL if (u << 1) != 0 else FP_ZERO
case 0xff: return FP_NAN if (u << 9) != 0 else FP_INFINITE
}
return FP_NORMAL
}
@(private)
_signbit :: #force_inline proc(x: double) -> int {
return int(transmute(uint64_t)x >> 63)
}
@(private)
_signbitf :: #force_inline proc(x: float) -> int {
return int(transmute(uint32_t)x >> 31)
}
isfinite :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
return fpclassify(x) == FP_INFINITE
}
isinf :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
return fpclassify(x) > FP_INFINITE
}
isnan :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
return fpclassify(x) == FP_NAN
}
isnormal :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
return fpclassify(x) == FP_NORMAL
}
// These are special in that they avoid float exceptions. They cannot just be
// implemented as the relational comparisons, as that would produce an invalid
// "sticky" state that propagates and affects maths results. These need
// to be implemented natively in Odin assuming isunordered to prevent that.
isgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
return !isunordered(x, y) && x > y
}
isgreaterequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
return !isunordered(x, y) && x >= y
}
isless :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
return !isunordered(x, y) && x < y
}
islessequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
return !isunordered(x, y) && x <= y
}
islessgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
return !isunordered(x, y) && x <= y
}
isunordered :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
if isnan(x) {
// Force evaluation of y to propagate exceptions for ordering semantics.
// To ensure correct semantics of IEEE 754 this cannot be compiled away.
sink: T
intrinsics.volatile_store(&sink, intrinsics.volatile_load(&y))
return true
}
return isnan(y)
}
fpclassify :: proc{_fpclassify, _fpclassifyf}
signbit :: proc{_signbit, _signbitf}
// Emulate tgmath.h behavior with explicit procedure overloading here.
acos :: proc{libc_acos, libc_acosf, cacos, cacosf}
asin :: proc{libc_asin, libc_asinf, casin, casinf}
atan :: proc{libc_atan, libc_atanf, catan, catanf}
atan2 :: proc{libc_atan2, libc_atan2f}
cos :: proc{libc_cos, libc_cosf, ccos, ccosf}
sin :: proc{libc_sin, libc_sinf, csin, csinf}
tan :: proc{libc_tan, libc_tanf, ctan, ctanf}
acosh :: proc{libc_acosh, libc_acoshf, cacosh, cacoshf}
asinh :: proc{libc_asinh, libc_asinhf, casinh, casinhf}
atanh :: proc{libc_atanh, libc_atanhf, catanh, catanhf}
cosh :: proc{libc_cosh, libc_coshf, ccosh, ccoshf}
sinh :: proc{libc_sinh, libc_sinhf, csinh, csinhf}
tanh :: proc{libc_tanh, libc_tanhf, ctanh, ctanhf}
exp :: proc{libc_exp, libc_expf, cexp, cexpf}
exp2 :: proc{libc_exp2, libc_exp2f}
expm1 :: proc{libc_expm1, libc_expm1f}
frexp :: proc{libc_frexp, libc_frexpf}
ilogb :: proc{libc_ilogb, libc_ilogbf}
ldexp :: proc{libc_ldexp, libc_ldexpf}
log :: proc{libc_log, libc_logf, clog, clogf}
log10 :: proc{libc_log10, libc_log10f}
log1p :: proc{libc_log1p, libc_log1pf}
log2 :: proc{libc_log2, libc_log2f}
logb :: proc{libc_logb, libc_logbf}
modf :: proc{libc_modf, libc_modff}
scalbn :: proc{libc_scalbn, libc_scalbnf}
scalbln :: proc{libc_scalbln, libc_scalblnf}
cbrt :: proc{libc_cbrt, libc_cbrtf}
fabs :: proc{libc_fabs, libc_fabsf, cabs, cabsf}
hypot :: proc{libc_hypot, libc_hypotf}
pow :: proc{libc_pow, libc_powf, cpow, cpowf}
sqrt :: proc{libc_sqrt, libc_sqrtf, csqrt, csqrtf}
erf :: proc{libc_erf, libc_erff}
erfc :: proc{libc_erfc, libc_erfcf}
lgamma :: proc{libc_lgamma, libc_lgammaf}
tgamma :: proc{libc_tgamma, libc_tgammaf}
ceil :: proc{libc_ceil, libc_ceilf}
floor :: proc{libc_floor, libc_floorf}
nearbyint :: proc{libc_nearbyint, libc_nearbyintf}
rint :: proc{libc_rint, libc_rintf}
lrint :: proc{libc_lrint, libc_lrintf}
llrint :: proc{libc_llrint, libc_llrintf}
round :: proc{libc_round, libc_roundf}
lround :: proc{libc_lround, libc_lroundf}
llround :: proc{libc_llround, libc_llroundf}
trunc :: proc{libc_trunc, libc_truncf}
fmod :: proc{libc_fmod, libc_fmodf}
remainder :: proc{libc_remainder, libc_remainderf}
remquo :: proc{libc_remquo, libc_remquof}
copysign :: proc{libc_copysign, libc_copysignf}
nextafter :: proc{libc_nextafter, libc_nextafterf}
fdim :: proc{libc_fdim, libc_fdimf}
fmax :: proc{libc_fmax, libc_fmaxf}
fmin :: proc{libc_fmin, libc_fminf}
fma :: proc{libc_fma, libc_fmaf}
// But retain the 'f' suffix-variant functions as well so they can be used,
// a trick is used here where we use explicit procedrual overloading of one
// procedure. This is done because the foreign block is marked @(private) and
// aliasing functions does not remove privateness from the entity.
acosf :: proc{libc_acosf}
asinf :: proc{libc_asinf}
atanf :: proc{libc_atanf}
atan2f :: proc{libc_atan2f}
cosf :: proc{libc_cosf}
sinf :: proc{libc_sinf}
tanf :: proc{libc_tanf}
acoshf :: proc{libc_acoshf}
asinhf :: proc{libc_asinhf}
atanhf :: proc{libc_atanhf}
coshf :: proc{libc_coshf}
sinhf :: proc{libc_sinhf}
tanhf :: proc{libc_tanhf}
expf :: proc{libc_expf}
exp2f :: proc{libc_exp2f}
expm1f :: proc{libc_expm1f}
frexpf :: proc{libc_frexpf}
ilogbf :: proc{libc_ilogbf}
ldexpf :: proc{libc_ldexpf}
logf :: proc{libc_logf}
log10f :: proc{libc_log10f}
log1pf :: proc{libc_log1pf}
log2f :: proc{libc_log2f}
logbf :: proc{libc_logbf}
modff :: proc{libc_modff}
scalbnf :: proc{libc_scalbnf}
scalblnf :: proc{libc_scalblnf}
cbrtf :: proc{libc_cbrtf}
fabsf :: proc{libc_fabsf}
hypotf :: proc{libc_hypotf}
powf :: proc{libc_powf}
sqrtf :: proc{libc_sqrtf}
erff :: proc{libc_erff}
erfcf :: proc{libc_erfcf}
lgammaf :: proc{libc_lgammaf}
tgammaf :: proc{libc_tgammaf}
ceilf :: proc{libc_ceilf}
floorf :: proc{libc_floorf}
nearbyintf :: proc{libc_nearbyintf}
rintf :: proc{libc_rintf}
lrintf :: proc{libc_lrintf}
llrintf :: proc{libc_llrintf}
roundf :: proc{libc_roundf}
lroundf :: proc{libc_lroundf}
llroundf :: proc{libc_llroundf}
truncf :: proc{libc_truncf}
fmodf :: proc{libc_fmodf}
remainderf :: proc{libc_remainderf}
remquof :: proc{libc_remquof}
copysignf :: proc{libc_copysignf}
nextafterf :: proc{libc_nextafterf}
fdimf :: proc{libc_fdimf}
fmaxf :: proc{libc_fmaxf}
fminf :: proc{libc_fminf}
fmaf :: proc{libc_fmaf}
// These two functions are special and not made type generic in tgmath.h since
// they only differ by their return type.
nan :: proc{libc_nan}
nanf :: proc{libc_nanf}
+66
View File
@@ -0,0 +1,66 @@
package libc
// 7.13 Nonlocal jumps
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
when ODIN_OS == .Windows {
@(default_calling_convention="c")
foreign libc {
// 7.13.1 Save calling environment
//
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
// necessarily export a symbol named setjmp but rather _setjmp in the case
// of musl, glibc, BSD libc, and msvcrt.
//
/// NOTE(dweiler): UCRT has two implementations of longjmp. One that performs
// stack unwinding and one that doesn't. The choice of which to use depends on a
// flag which is set inside the jmp_buf structure given to setjmp. The default
// behavior is to unwind the stack. Within Odin, we cannot use the stack
// unwinding version as the unwinding information isn't present. To opt-in to
// the regular non-unwinding version we need a way to set this flag. Since the
// location of the flag within the struct is not defined or part of the ABI and
// can change between versions of UCRT, we must rely on setjmp to set it. It
// turns out that setjmp receives this flag in the RDX register on Win64, this
// just so happens to coincide with the second argument of a function in the
// Win64 ABI. By giving our setjmp a second argument with the value of zero,
// the RDX register will contain zero and correctly set the flag to disable
// stack unwinding.
@(link_name="_setjmp")
setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---
}
} else {
@(default_calling_convention="c")
foreign libc {
// 7.13.1 Save calling environment
//
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
// necessarily export a symbol named setjmp but rather _setjmp in the case
// of musl, glibc, BSD libc, and msvcrt.
@(link_name="_setjmp")
setjmp :: proc(env: ^jmp_buf) -> int ---
}
}
@(default_calling_convention="c")
foreign libc {
// 7.13.2 Restore calling environment
longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---
}
// The C99 Rationale describes jmp_buf as being an array type for backward
// compatibility. Odin does not need to honor this and couldn't as arrays in
// Odin don't decay to pointers. It is somewhat easy for us to bind this, we
// just need to ensure the structure contains enough storage with appropriate
// alignment. Since there are no types in C with an alignment larger than
// that of max_align_t, which cannot be larger than sizeof(long double) as any
// other exposed type wouldn't be valid C, the maximum alignment possible in a
// strictly conformant C implementation is 16 on the platforms we care about.
// The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms.
jmp_buf :: struct #align 16 { _: [4096]char, }
+61
View File
@@ -0,0 +1,61 @@
package libc
// 7.14 Signal handling
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
sig_atomic_t :: distinct atomic_int
SIG_ATOMIC_MIN :: min(sig_atomic_t)
SIG_ATOMIC_MAX :: max(sig_atomic_t)
@(default_calling_convention="c")
foreign libc {
signal :: proc(sig: int, func: proc "c" (int)) -> proc "c" (int) ---
raise :: proc(sig: int) -> int ---
}
when ODIN_OS == .Windows {
SIG_ERR :: rawptr(~uintptr(0))
SIG_DFL :: rawptr(uintptr(0))
SIG_IGN :: rawptr(uintptr(1))
SIGABRT :: 22
SIGFPE :: 8
SIGILL :: 4
SIGINT :: 2
SIGSEGV :: 11
SIGTERM :: 15
}
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
SIG_ERR :: rawptr(~uintptr(0))
SIG_DFL :: rawptr(uintptr(0))
SIG_IGN :: rawptr(uintptr(1))
SIGABRT :: 6
SIGFPE :: 8
SIGILL :: 4
SIGINT :: 2
SIGSEGV :: 11
SIGTERM :: 15
}
when ODIN_OS == .Darwin {
SIG_ERR :: rawptr(~uintptr(0))
SIG_DFL :: rawptr(uintptr(0))
SIG_IGN :: rawptr(uintptr(1))
SIGABRT :: 6
SIGFPE :: 8
SIGILL :: 4
SIGINT :: 2
SIGSEGV :: 11
SIGTERM :: 15
}
+41
View File
@@ -0,0 +1,41 @@
package libc
// 7.16 Variable arguments
import "core:intrinsics"
@(private="file")
@(default_calling_convention="none")
foreign _ {
@(link_name="llvm.va_start") _va_start :: proc(arglist: ^i8) ---
@(link_name="llvm.va_end") _va_end :: proc(arglist: ^i8) ---
@(link_name="llvm.va_copy") _va_copy :: proc(dst, src: ^i8) ---
}
// Since there are no types in C with an alignment larger than that of
// max_align_t, which cannot be larger than sizeof(long double) as any other
// exposed type wouldn't be valid C, the maximum alignment possible in a
// strictly conformant C implementation is 16 on the platforms we care about.
// The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms.
va_list :: struct #align 16 {
_: [4096]u8,
}
va_start :: #force_inline proc(ap: ^va_list, _: any) {
_va_start(cast(^i8)ap)
}
va_end :: #force_inline proc(ap: ^va_list) {
_va_end(cast(^i8)ap)
}
va_copy :: #force_inline proc(dst, src: ^va_list) {
_va_copy(cast(^i8)dst, cast(^i8)src)
}
// We cannot provide va_arg as there is no way to create "C" style procedures
// in Odin which take variable arguments the C way. The #c_vararg attribute only
// exists for foreign imports. That being said, being able to copy a va_list,
// as well as start and end one is necessary in some functions, the va_list
// taking functions in libc as an example.
+381
View File
@@ -0,0 +1,381 @@
package libc
// 7.17 Atomics
import "core:intrinsics"
ATOMIC_BOOL_LOCK_FREE :: true
ATOMIC_CHAR_LOCK_FREE :: true
ATOMIC_CHAR16_T_LOCK_FREE :: true
ATOMIC_CHAR32_T_LOCK_FREE :: true
ATOMIC_WCHAR_T_LOCK_FREE :: true
ATOMIC_SHORT_LOCK_FREE :: true
ATOMIC_INT_LOCK_FREE :: true
ATOMIC_LONG_LOCK_FREE :: true
ATOMIC_LLONG_LOCK_FREE :: true
ATOMIC_POINTER_LOCK_FREE :: true
// 7.17.3 Order and consistency
memory_order :: enum int {
relaxed,
consume,
acquire,
release,
acq_rel,
seq_cst,
}
memory_order_relaxed :: memory_order.relaxed
memory_order_consume :: memory_order.consume
memory_order_acquire :: memory_order.acquire
memory_order_release :: memory_order.release
memory_order_acq_rel :: memory_order.acq_rel
memory_order_seq_cst :: memory_order.seq_cst
// 7.17.2 Initialization
ATOMIC_VAR_INIT :: #force_inline proc(value: $T) -> T {
return value
}
atomic_init :: #force_inline proc(obj: ^$T, value: T) {
intrinsics.atomic_store(obj, value)
}
kill_dependency :: #force_inline proc(value: $T) -> T {
return value
}
// 7.17.4 Fences
atomic_thread_fence :: #force_inline proc(order: memory_order) {
assert(order != .relaxed)
assert(order != .consume)
#partial switch order {
case .acquire: intrinsics.atomic_thread_fence(.Acquire)
case .release: intrinsics.atomic_thread_fence(.Release)
case .acq_rel: intrinsics.atomic_thread_fence(.Acq_Rel)
case .seq_cst: intrinsics.atomic_thread_fence(.Seq_Cst)
}
}
atomic_signal_fence :: #force_inline proc(order: memory_order) {
assert(order != .relaxed)
assert(order != .consume)
#partial switch order {
case .acquire: intrinsics.atomic_signal_fence(.Acquire)
case .release: intrinsics.atomic_signal_fence(.Release)
case .acq_rel: intrinsics.atomic_signal_fence(.Acq_Rel)
case .seq_cst: intrinsics.atomic_signal_fence(.Seq_Cst)
}
}
// 7.17.5 Lock-free property
atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
return intrinsics.atomic_type_is_lock_free(T)
}
// 7.17.6 Atomic integer types
atomic_bool :: distinct bool
atomic_char :: distinct char
atomic_schar :: distinct char
atomic_uchar :: distinct uchar
atomic_short :: distinct short
atomic_ushort :: distinct ushort
atomic_int :: distinct int
atomic_uint :: distinct uint
atomic_long :: distinct long
atomic_ulong :: distinct ulong
atomic_llong :: distinct longlong
atomic_ullong :: distinct ulonglong
atomic_char16_t :: distinct char16_t
atomic_char32_t :: distinct char32_t
atomic_wchar_t :: distinct wchar_t
atomic_int_least8_t :: distinct int_least8_t
atomic_uint_least8_t :: distinct uint_least8_t
atomic_int_least16_t :: distinct int_least16_t
atomic_uint_least16_t :: distinct uint_least16_t
atomic_int_least32_t :: distinct int_least32_t
atomic_uint_least32_t :: distinct uint_least32_t
atomic_int_least64_t :: distinct int_least64_t
atomic_uint_least64_t :: distinct uint_least64_t
atomic_int_fast8_t :: distinct int_fast8_t
atomic_uint_fast8_t :: distinct uint_fast8_t
atomic_int_fast16_t :: distinct int_fast16_t
atomic_uint_fast16_t :: distinct uint_fast16_t
atomic_int_fast32_t :: distinct int_fast32_t
atomic_uint_fast32_t :: distinct uint_fast32_t
atomic_int_fast64_t :: distinct int_fast64_t
atomic_uint_fast64_t :: distinct uint_fast64_t
atomic_intptr_t :: distinct intptr_t
atomic_uintptr_t :: distinct uintptr_t
atomic_size_t :: distinct size_t
atomic_ptrdiff_t :: distinct ptrdiff_t
atomic_intmax_t :: distinct intmax_t
atomic_uintmax_t :: distinct uintmax_t
// 7.17.7 Operations on atomic types
atomic_store :: #force_inline proc(object: ^$T, desired: T) {
intrinsics.atomic_store(object, desired)
}
atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) {
assert(order != .consume)
assert(order != .acquire)
assert(order != .acq_rel)
#partial switch order {
case .relaxed: intrinsics.atomic_store_explicit(object, desired, .Relaxed)
case .release: intrinsics.atomic_store_explicit(object, desired, .Release)
case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .Seq_Cst)
}
}
atomic_load :: #force_inline proc(object: ^$T) -> T {
return intrinsics.atomic_load(object)
}
atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) {
assert(order != .release)
assert(order != .acq_rel)
#partial switch order {
case .relaxed: return intrinsics.atomic_load_explicit(object, .Relaxed)
case .consume: return intrinsics.atomic_load_explicit(object, .Consume)
case .acquire: return intrinsics.atomic_load_explicit(object, .Acquire)
case .seq_cst: return intrinsics.atomic_load_explicit(object, .Seq_Cst)
}
}
atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
return intrinsics.atomic_exchange(object, desired)
}
atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
switch order {
case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .Relaxed)
case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .Consume)
case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .Acquire)
case .release: return intrinsics.atomic_exchange_explicit(object, desired, .Release)
case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .Acq_Rel)
case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .Seq_Cst)
}
return false
}
// C does not allow failure memory order to be order_release or acq_rel.
// Similarly, it does not allow the failure order to be stronger than success
// order. Since consume and acquire are both monotonic, we can count them as
// one, for a total of three memory orders that are relevant in compare exchange.
// relaxed, acquire (consume), seq_cst.
// The requirement that the failure order cannot be stronger than success limits
// the valid combinations for the failure order to this table:
// [success = seq_cst, failure = seq_cst] => _
// [success = acquire, failure = seq_cst] => acq
// [success = release, failure = seq_cst] => rel
// [success = acq_rel, failure = seq_cst] => acqrel
// [success = relaxed, failure = relaxed] => relaxed
// [success = seq_cst, failure = relaxed] => failrelaxed
// [success = seq_cst, failure = acquire] => failacq
// [success = acquire, failure = relaxed] => acq_failrelaxed
// [success = acq_rel, failure = relaxed] => acqrel_failrelaxed
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
value, ok := intrinsics.atomic_compare_exchange_strong(object, expected^, desired)
if !ok { expected^ = value }
return ok
}
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) -> bool {
assert(failure != .release)
assert(failure != .acq_rel)
value: T; ok: bool
#partial switch failure {
case .seq_cst:
assert(success != .relaxed)
#partial switch success {
case .seq_cst:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
case .acquire:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
case .consume:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Seq_Cst)
case .release:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Release, .Seq_Cst)
case .acq_rel:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
}
case .relaxed:
assert(success != .release)
#partial switch success {
case .relaxed:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Relaxed, .Relaxed)
case .seq_cst:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
case .acquire:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Relaxed)
case .consume:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Relaxed)
case .acq_rel:
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
}
case .consume:
assert(success == .seq_cst)
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Consume)
case .acquire:
assert(success == .seq_cst)
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
}
if !ok { expected^ = value }
return ok
}
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
value, ok := intrinsics.atomic_compare_exchange_weak(object, expected^, desired)
if !ok { expected^ = value }
return ok
}
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) -> bool {
assert(failure != .release)
assert(failure != .acq_rel)
value: T; ok: bool
#partial switch failure {
case .seq_cst:
assert(success != .relaxed)
#partial switch success {
case .seq_cst:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
case .acquire:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
case .consume:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Seq_Cst)
case .release:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Release, .Seq_Cst)
case .acq_rel:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
}
case .relaxed:
assert(success != .release)
#partial switch success {
case .relaxed:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Relaxed, .Relaxed)
case .seq_cst:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
case .acquire:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Relaxed)
case .consume:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Relaxed)
case .acq_rel:
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
}
case .consume:
assert(success == .seq_cst)
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Consume)
case .acquire:
assert(success == .seq_cst)
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
}
if !ok { expected^ = value }
return ok
}
// 7.17.7.5 The atomic_fetch and modify generic functions
atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T {
return intrinsics.atomic_add(object, operand)
}
atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
switch order {
case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .Relaxed)
case .consume: return intrinsics.atomic_add_explicit(object, operand, .Consume)
case .acquire: return intrinsics.atomic_add_explicit(object, operand, .Acquire)
case .release: return intrinsics.atomic_add_explicit(object, operand, .Release)
case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .Acq_Rel)
case: fallthrough
case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .Seq_Cst)
}
}
atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T {
return intrinsics.atomic_sub(object, operand)
}
atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
switch order {
case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .Relaxed)
case .consume: return intrinsics.atomic_sub_explicit(object, operand, .Consume)
case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .Acquire)
case .release: return intrinsics.atomic_sub_explicit(object, operand, .Release)
case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .Acq_Rel)
case: fallthrough
case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .Seq_Cst)
}
}
atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T {
return intrinsics.atomic_or(object, operand)
}
atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
switch order {
case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .Relaxed)
case .consume: return intrinsics.atomic_or_explicit(object, operand, .Consume)
case .acquire: return intrinsics.atomic_or_explicit(object, operand, .Acquire)
case .release: return intrinsics.atomic_or_explicit(object, operand, .Release)
case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .Acq_Rel)
case: fallthrough
case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .Seq_Cst)
}
}
atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T {
return intrinsics.atomic_xor(object, operand)
}
atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
switch order {
case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .Relaxed)
case .consume: return intrinsics.atomic_xor_explicit(object, operand, .Consume)
case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .Acquire)
case .release: return intrinsics.atomic_xor_explicit(object, operand, .Release)
case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .Acq_Rel)
case: fallthrough
case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .Seq_Cst)
}
}
atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T {
return intrinsics.atomic_and(object, operand)
}
atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
switch order {
case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .Relaxed)
case .consume: return intrinsics.atomic_and_explicit(object, operand, .Consume)
case .acquire: return intrinsics.atomic_and_explicit(object, operand, .Acquire)
case .release: return intrinsics.atomic_and_explicit(object, operand, .Release)
case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .Acq_Rel)
case: fallthrough
case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .Seq_Cst)
}
}
// 7.17.8 Atomic flag type and operations
atomic_flag :: distinct atomic_bool
atomic_flag_test_and_set :: #force_inline proc(flag: ^atomic_flag) -> bool {
return bool(atomic_exchange(flag, atomic_flag(true)))
}
atomic_flag_test_and_set_explicit :: #force_inline proc(flag: ^atomic_flag, order: memory_order) -> bool {
return bool(atomic_exchange_explicit(flag, atomic_flag(true), order))
}
atomic_flag_clear :: #force_inline proc(flag: ^atomic_flag) {
atomic_store(flag, atomic_flag(false))
}
atomic_flag_clear_explicit :: #force_inline proc(flag: ^atomic_flag, order: memory_order) {
atomic_store_explicit(flag, atomic_flag(false), order)
}
+217
View File
@@ -0,0 +1,217 @@
package libc
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
// 7.21 Input/output
FILE :: struct {}
// MSVCRT compatible.
when ODIN_OS == .Windows {
_IOFBF :: 0x0000
_IONBF :: 0x0004
_IOLBF :: 0x0040
BUFSIZ :: 512
EOF :: int(-1)
FOPEN_MAX :: 20
FILENAME_MAX :: 260
L_tmpnam :: 15 // "\\" + 12 + NUL
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 32767 // SHRT_MAX
fpos_t :: distinct i64
@(private="file")
@(default_calling_convention="c")
foreign libc {
__acrt_iob_func :: proc (index: uint) -> ^FILE ---
}
stdin := __acrt_iob_func(0)
stdout := __acrt_iob_func(1)
stderr := __acrt_iob_func(2)
}
// GLIBC and MUSL compatible.
when ODIN_OS == .Linux {
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 2
BUFSIZ :: 1024
EOF :: int(-1)
FOPEN_MAX :: 1000
FILENAME_MAX :: 4096
L_tmpnam :: 20
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 308915776
foreign libc {
stderr: ^FILE
stdin: ^FILE
stdout: ^FILE
}
}
when ODIN_OS == .OpenBSD {
fpos_t :: distinct i64
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 1
BUFSIZ :: 1024
EOF :: int(-1)
FOPEN_MAX :: 20
FILENAME_MAX :: 1024
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
foreign libc {
stderr: ^FILE
stdin: ^FILE
stdout: ^FILE
}
}
when ODIN_OS == .FreeBSD {
fpos_t :: distinct i64
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 1
BUFSIZ :: 1024
EOF :: int(-1)
FOPEN_MAX :: 20
FILENAME_MAX :: 1024
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
foreign libc {
stderr: ^FILE
stdin: ^FILE
stdout: ^FILE
}
}
when ODIN_OS == .Darwin {
fpos_t :: distinct i64
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 2
BUFSIZ :: 1024
EOF :: int(-1)
FOPEN_MAX :: 20
FILENAME_MAX :: 1024
L_tmpnam :: 1024
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 308915776
foreign libc {
@(link_name="__stderrp") stderr: ^FILE
@(link_name="__stdinp") stdin: ^FILE
@(link_name="__stdoutp") stdout: ^FILE
}
}
@(default_calling_convention="c")
foreign libc {
// 7.21.4 Operations on files
remove :: proc(filename: cstring) -> int ---
rename :: proc(old, new: cstring) -> int ---
tmpfile :: proc() -> ^FILE ---
tmpnam :: proc(s: [^]char) -> [^]char ---
// 7.21.5 File access functions
fclose :: proc(stream: ^FILE) -> int ---
fflush :: proc(stream: ^FILE) -> int ---
fopen :: proc(filename, mode: cstring) -> ^FILE ---
freopen :: proc(filename, mode: cstring, stream: ^FILE) -> ^FILE ---
setbuf :: proc(stream: ^FILE, buf: [^]char) ---
setvbuf :: proc(stream: ^FILE, buf: [^]char, mode: int, size: size_t) -> int ---
// 7.21.6 Formatted input/output functions
fprintf :: proc(stream: ^FILE, format: cstring, #c_vararg args: ..any) -> int ---
fscanf :: proc(stream: ^FILE, format: cstring, #c_vararg args: ..any) -> int ---
printf :: proc(format: cstring, #c_vararg args: ..any) -> int ---
scanf :: proc(format: cstring, #c_vararg args: ..any) -> int ---
snprintf :: proc(s: [^]char, format: cstring, #c_vararg args: ..any) -> int ---
sscanf :: proc(s, format: cstring, #c_vararg args: ..any) -> int ---
vfprintf :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---
vfscanf :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---
vprintf :: proc(format: cstring, arg: ^va_list) -> int ---
vscanf :: proc(format: cstring, arg: ^va_list) -> int ---
vsnprintf :: proc(s: [^]char, n: size_t, format: cstring, arg: ^va_list) -> int ---
vsprintf :: proc(s: [^]char, format: cstring, arg: ^va_list) -> int ---
vsscanf :: proc(s, format: cstring, arg: ^va_list) -> int ---
// 7.21.7 Character input/output functions
fgetc :: proc(stream: ^FILE) -> int ---
fgets :: proc(s: [^]char, n: int, stream: ^FILE) -> [^]char ---
fputc :: proc(s: cstring, stream: ^FILE) -> int ---
getc :: proc(stream: ^FILE) -> int ---
getchar :: proc() -> int ---
putc :: proc(c: int, stream: ^FILE) -> int ---
putchar :: proc() -> int ---
puts :: proc(s: cstring) -> int ---
ungetc :: proc(c: int, stream: ^FILE) -> int ---
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
// 7.21.9 File positioning functions
fgetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---
fseek :: proc(stream: ^FILE, offset: long, whence: int) -> int ---
fsetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---
ftell :: proc(stream: ^FILE) -> long ---
rewind :: proc(stream: ^FILE) ---
// 7.21.10 Error-handling functions
clearerr :: proc(stream: ^FILE) ---
feof :: proc(stream: ^FILE) -> int ---
ferror :: proc(stream: ^FILE) -> int ---
perror :: proc(s: cstring) ---
}
+127
View File
@@ -0,0 +1,127 @@
package libc
// 7.22 General utilities
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
when ODIN_OS == .Windows {
RAND_MAX :: 0x7fff
@(private="file")
@(default_calling_convention="c")
foreign libc {
___mb_cur_max_func :: proc() -> int ---
}
MB_CUR_MAX :: #force_inline proc() -> size_t {
return size_t(___mb_cur_max_func())
}
}
when ODIN_OS == .Linux {
RAND_MAX :: 0x7fffffff
// GLIBC and MUSL only
@(private="file")
@(default_calling_convention="c")
foreign libc {
__ctype_get_mb_cur_max :: proc() -> size_t ---
}
MB_CUR_MAX :: #force_inline proc() -> size_t {
return size_t(__ctype_get_mb_cur_max())
}
}
when ODIN_OS == .Darwin {
RAND_MAX :: 0x7fffffff
// GLIBC and MUSL only
@(private="file")
@(default_calling_convention="c")
foreign libc {
___mb_cur_max :: proc() -> int ---
}
MB_CUR_MAX :: #force_inline proc() -> size_t {
return size_t(___mb_cur_max())
}
}
// C does not declare what these values should be, as an implementation is free
// to use any two distinct values it wants to indicate success or failure.
// However, nobody actually does and everyone appears to have agreed upon these
// values.
EXIT_SUCCESS :: 0
EXIT_FAILURE :: 1
// C does not declare which order 'quot' and 'rem' should be for the divide
// structures. An implementation could put 'rem' first. However, nobody actually
// does and everyone appears to have agreed upon this layout.
div_t :: struct { quot, rem: int, }
ldiv_t :: struct { quot, rem: long, }
lldiv_t :: struct { quot, rem: longlong, }
@(default_calling_convention="c")
foreign libc {
// 7.22.1 Numeric conversion functions
atof :: proc(nptr: cstring) -> double ---
atoi :: proc(nptr: cstring) -> int ---
atol :: proc(nptr: cstring) -> long ---
atoll :: proc(nptr: cstring) -> longlong ---
strtod :: proc(nptr: cstring, endptr: ^[^]char) -> double ---
strtof :: proc(nptr: cstring, endptr: ^[^]char) -> float ---
strtol :: proc(nptr: cstring, endptr: ^[^]char, base: int) -> long ---
strtoll :: proc(nptr: cstring, endptr: ^[^]char, base: int) -> longlong ---
strtoul :: proc(nptr: cstring, endptr: ^[^]char, base: int) -> ulong ---
strtoull :: proc(nptr: cstring, endptr: ^[^]char, base: int) -> ulonglong ---
// 7.22.2 Pseudo-random sequence generation functions
rand :: proc() -> int ---
srand :: proc(seed: uint) ---
// 7.22.3 Memory management functions
aligned_alloc :: proc(aligment, size: size_t) -> rawptr ---
calloc :: proc(nmemb, size: size_t) -> rawptr ---
free :: proc(ptr: rawptr) ---
malloc :: proc(size: size_t) -> rawptr ---
realloc :: proc(ptr: rawptr, size: size_t) -> rawptr ---
// 7.22.4 Communication with the environment
abort :: proc() -> ! ---
atexit :: proc(func: proc "c" ()) -> int ---
at_quick_exit :: proc(func: proc "c" ()) -> int ---
exit :: proc(status: int) -> ! ---
_Exit :: proc(status: int) -> ! ---
getenv :: proc(name: cstring) -> [^]char ---
quick_exit :: proc(status: int) -> ! ---
system :: proc(cmd: cstring) -> int ---
// 7.22.5 Searching and sorting utilities
bsearch :: proc(key, base: rawptr, nmemb, size: size_t, compar: proc "c" (lhs, rhs: rawptr) -> int) -> rawptr ---
qsort :: proc(base: rawptr, nmemb, size: size_t, compar: proc "c" (lhs, rhs: rawptr) -> int) ---
// 7.22.6 Integer arithmetic functions
abs :: proc(j: int) -> int ---
labs :: proc(j: long) -> long ---
llabs :: proc(j: longlong) -> longlong ---
div :: proc(numer, denom: int) -> div_t ---
ldiv :: proc(numer, denom: long) -> ldiv_t ---
lldiv :: proc(numer, denom: longlong) -> lldiv_t ---
// 7.22.7 Multibyte/wide character conversion functions
mblen :: proc(s: cstring, n: size_t) -> int ---
mbtowc :: proc(pwc: ^wchar_t, s: cstring, n: size_t) -> int ---
wctomb :: proc(s: [^]char, wc: wchar_t) -> int ---
// 7.22.8 Multibyte/wide string conversion functions
mbstowcs :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---
wcstombs :: proc(s: [^]char, pwcs: ^wchar_t, n: size_t) -> size_t ---
}
+48
View File
@@ -0,0 +1,48 @@
package libc
import "core:runtime"
// 7.24 String handling
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
foreign libc {
// 7.24.2 Copying functions
memcpy :: proc(s1, s2: rawptr, n: size_t) -> rawptr ---
memmove :: proc(s1, s2: rawptr, n: size_t) -> rawptr ---
strcpy :: proc(s1: [^]char, s2: cstring) -> [^]char ---
strncpy :: proc(s1: [^]char, s2: cstring, n: size_t) -> [^]char ---
// 7.24.3 Concatenation functions
strcat :: proc(s1: [^]char, s2: cstring) -> [^]char ---
strncat :: proc(s1: [^]char, s2: cstring, n: size_t) -> [^]char ---
// 7.24.4 Comparison functions
memcmp :: proc(s1, s2: rawptr, n: size_t) -> int ---
strcmp :: proc(s1, s2: cstring) -> int ---
strcoll :: proc(s1, s2: cstring) -> int ---
strncmp :: proc(s1, s2: cstring, n: size_t) -> int ---
strxfrm :: proc(s1: [^]char, s2: cstring, n: size_t) -> size_t ---
// 7.24.5 Search functions
memchr :: proc(s: rawptr, c: int, n: size_t) -> rawptr ---
strchr :: proc(s: cstring, c: int) -> [^]char ---
strcspn :: proc(s1, s2: cstring) -> size_t ---
strpbrk :: proc(s1, s2: cstring) -> [^]char ---
strrchr :: proc(s: [^]char, c: int) -> [^]char ---
strcpn :: proc(s1, s2: cstring) -> [^]char ---
strtok :: proc(s1: [^]char, s2: cstring) -> [^]char ---
// 7.24.6 Miscellaneous functions
strerror :: proc(errnum: int) -> [^]char ---
strlen :: proc(s: cstring) -> size_t ---
}
memset :: proc "c" (s: rawptr, c: int, n: size_t) -> rawptr {
return runtime.memset(s, c, auto_cast n)
}
+50
View File
@@ -0,0 +1,50 @@
package libc_tests
import "core:c/libc"
test_stdio :: proc() {
c: libc.char = 'C';
libc.puts("Hello from puts");
libc.printf("Hello from printf in %c\n", c);
}
test_thread :: proc() {
thread_proc :: proc "c" (rawptr) -> libc.int {
libc.printf("Hello from thread");
return 42;
}
thread: libc.thrd_t;
libc.thrd_create(&thread, thread_proc, nil);
result: libc.int;
libc.thrd_join(thread, &result);
libc.printf(" %d\n", result);
}
jmp: libc.jmp_buf;
test_sjlj :: proc() {
if libc.setjmp(&jmp) != 0 {
libc.printf("Hello from longjmp\n");
return;
}
libc.printf("Hello from setjmp\n");
libc.longjmp(&jmp, 1);
}
test_signal :: proc() {
handler :: proc "c" (sig: libc.int) {
libc.printf("Hello from signal handler\n");
}
libc.signal(libc.SIGABRT, handler);
libc.raise(libc.SIGABRT);
}
test_atexit :: proc() {
handler :: proc "c" () {
libc.printf("Hello from atexit\n");
}
libc.atexit(handler);
}
main :: proc() {
test_stdio();
test_thread();
test_sjlj();
test_signal();
test_atexit();
}
+143
View File
@@ -0,0 +1,143 @@
package libc
// 7.26 Threads
thrd_start_t :: proc "c" (rawptr) -> int
tss_dtor_t :: proc "c" (rawptr)
when ODIN_OS == .Windows {
foreign import libc {
"system:libucrt.lib",
"system:msvcprt.lib"
}
thrd_success :: 0 // _Thrd_success
thrd_nomem :: 1 // _Thrd_nomem
thrd_timedout :: 2 // _Thrd_timedout
thrd_busy :: 3 // _Thrd_busy
thrd_error :: 4 // _Thrd_error
mtx_plain :: 1 // _Mtx_plain
mtx_recursive :: 0x100 // _Mtx_recursive
mtx_timed :: 4 // _Mtx_timed
TSS_DTOR_ITERATIONS :: 4 // _TSS_DTOR_ITERATIONS_IMP
once_flag :: distinct i8 // _Once_flag_imp_t
thrd_t :: struct { _: rawptr, _: uint, } // _Thrd_t
tss_t :: distinct int // _Tss_imp_t
cnd_t :: distinct rawptr // _Cnd_imp_t
mtx_t :: distinct rawptr // _Mtx_imp_t
// MSVCRT does not expose the C11 symbol names as what they are in C11
// because they held off implementing <threads.h> and C11 support for so
// long that people started implementing their own. To prevent symbol
// conflict with existing customers code they had to namespace them
// differently. Thus we need to alias the correct symbol names with Odin's
// link_name attribute.
@(default_calling_convention="c")
foreign libc {
// 7.26.2 Initialization functions
@(link_name="_Call_once") call_once :: proc(flag: ^once_flag, func: proc "c" ()) ---
// 7.26.3 Condition variable functions
@(link_name="_Cnd_broadcast") cnd_broadcast :: proc(cond: ^cnd_t) -> int ---
@(link_name="_Cnd_destroy") cnd_destroy :: proc(cond: ^cnd_t) ---
@(link_name="_Cnd_init") cnd_init :: proc(cond: ^cnd_t) -> int ---
@(link_name="_Cnd_signal") cnd_signal :: proc(cond: ^cnd_t) -> int ---
@(link_name="_Cnd_timedwait") cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
@(link_name="_Cnd_wait") cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
// 7.26.4 Mutex functions
@(link_name="_Mtx_destroy") mtx_destroy :: proc(mtx: ^mtx_t) ---
@(link_name="_Mtx_init") mtx_init :: proc(mtx: ^mtx_t, type: int) -> int ---
@(link_name="_Mtx_lock") mtx_lock :: proc(mtx: ^mtx_t) -> int ---
@(link_name="_Mtx_timedlock") mtx_timedlock :: proc(mtx: ^mtx_t, ts: ^timespec) -> int ---
@(link_name="_Mtx_trylock") mtx_trylock :: proc(mtx: ^mtx_t) -> int ---
@(link_name="_Mtx_unlock") mtx_unlock :: proc(mtx: ^mtx_t) -> int ---
// 7.26.5 Thread functions
@(link_name="_Thrd_create") thrd_create :: proc(thr: ^thrd_t, func: thrd_start_t, arg: rawptr) -> int ---
@(link_name="_Thrd_current") thrd_current :: proc() -> thrd_t ---
@(link_name="_Thrd_detach") thrd_detach :: proc(thr: thrd_t) -> int ---
@(link_name="_Thrd_equal") thrd_equal :: proc(lhs, rhs: thrd_t) -> int ---
@(link_name="_Thrd_exit") thrd_exit :: proc(res: int) -> ! ---
@(link_name="_Thrd_join") thrd_join :: proc(thr: thrd_t, res: ^int) -> int ---
@(link_name="_Thrd_sleep") thrd_sleep :: proc(duration, remaining: ^timespec) -> int ---
@(link_name="_Thrd_yield") thrd_yield :: proc() ---
// 7.26.6 Thread-specific storage functions
@(link_name="_Tss_create") tss_create :: proc(key: ^tss_t, dtor: tss_dtor_t) -> int ---
@(link_name="_Tss_delete") tss_delete :: proc(key: tss_t) ---
@(link_name="_Tss_get") tss_get :: proc(key: tss_t) -> rawptr ---
@(link_name="_Tss_set") tss_set :: proc(key: tss_t, val: rawptr) -> int ---
}
}
// GLIBC and MUSL compatible constants and types.
when ODIN_OS == .Linux {
foreign import libc {
"system:c",
"system:pthread"
}
thrd_success :: 0
thrd_busy :: 1
thrd_error :: 2
thrd_nomem :: 3
thrd_timedout :: 4
mtx_plain :: 0
mtx_recursive :: 1
mtx_timed :: 2
TSS_DTOR_ITERATIONS :: 4
once_flag :: distinct int
thrd_t :: distinct ulong
tss_t :: distinct uint
cnd_t :: struct #raw_union { _: [12]int, _: [12 * size_of(int) / size_of(rawptr)]rawptr, }
mtx_t :: struct #raw_union { _: [10 when size_of(long) == 8 else 6]int, _: [5 when size_of(long) == 8 else 6]rawptr, }
@(default_calling_convention="c")
foreign libc {
// 7.26.2 Initialization functions
call_once :: proc(flag: ^once_flag, func: proc "c" ()) ---
// 7.26.3 Condition variable functions
cnd_broadcast :: proc(cond: ^cnd_t) -> int ---
cnd_destroy :: proc(cond: ^cnd_t) ---
cnd_init :: proc(cond: ^cnd_t) -> int ---
cnd_signal :: proc(cond: ^cnd_t) -> int ---
cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
// 7.26.4 Mutex functions
mtx_destroy :: proc(mtx: ^mtx_t) ---
mtx_init :: proc(mtx: ^mtx_t, type: int) -> int ---
mtx_lock :: proc(mtx: ^mtx_t) -> int ---
mtx_timedlock :: proc(mtx: ^mtx_t, ts: ^timespec) -> int ---
mtx_trylock :: proc(mtx: ^mtx_t) -> int ---
mtx_unlock :: proc(mtx: ^mtx_t) -> int ---
// 7.26.5 Thread functions
thrd_create :: proc(thr: ^thrd_t, func: thrd_start_t, arg: rawptr) -> int ---
thrd_current :: proc() -> thrd_t ---
thrd_detach :: proc(thr: thrd_t) -> int ---
thrd_equal :: proc(lhs, rhs: thrd_t) -> int ---
thrd_exit :: proc(res: int) -> ! ---
thrd_join :: proc(thr: thrd_t, res: ^int) -> int ---
thrd_sleep :: proc(duration, remaining: ^timespec) -> int ---
thrd_yield :: proc() ---
// 7.26.6 Thread-specific storage functions
tss_create :: proc(key: ^tss_t, dtor: tss_dtor_t) -> int ---
tss_delete :: proc(key: tss_t) ---
tss_get :: proc(key: tss_t) -> rawptr ---
tss_set :: proc(key: tss_t, val: rawptr) -> int ---
}
}
when ODIN_OS == .Darwin {
// TODO: find out what this is meant to be!
}
+88
View File
@@ -0,0 +1,88 @@
package libc
// 7.27 Date and time
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
when ODIN_OS == .Windows {
foreign libc {
// 7.27.2 Time manipulation functions
clock :: proc() -> clock_t ---
@(link_name="_difftime64") difftime :: proc(time1, time2: time_t) -> double ---
mktime :: proc(timeptr: ^tm) -> time_t ---
@(link_name="_time64") time :: proc(timer: ^time_t) -> time_t ---
@(link_name="_timespec64_get") timespec_get :: proc(ts: ^timespec, base: int) -> int ---
// 7.27.3 Time conversion functions
asctime :: proc(timeptr: ^tm) -> [^]char ---
@(link_name="_ctime64") ctime :: proc(timer: ^time_t) -> [^]char ---
@(link_name="_gmtime64") gmtime :: proc(timer: ^time_t) -> ^tm ---
@(link_name="_localtime64") localtime :: proc(timer: ^time_t) -> ^tm ---
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
}
CLOCKS_PER_SEC :: 1000
TIME_UTC :: 1
clock_t :: distinct long
time_t :: distinct i64
timespec :: struct #align 8 {
tv_sec: time_t,
tv_nsec: long,
}
tm :: struct #align 8 {
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
}
}
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
@(default_calling_convention="c")
foreign libc {
// 7.27.2 Time manipulation functions
clock :: proc() -> clock_t ---
difftime :: proc(time1, time2: time_t) -> double ---
mktime :: proc(timeptr: ^tm) -> time_t ---
time :: proc(timer: ^time_t) -> time_t ---
timespec_get :: proc(ts: ^timespec, base: int) -> int ---
// 7.27.3 Time conversion functions
asctime :: proc(timeptr: ^tm) -> [^]char ---
ctime :: proc(timer: ^time_t) -> [^]char ---
gmtime :: proc(timer: ^time_t) -> ^tm ---
localtime :: proc(timer: ^time_t) -> ^tm ---
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
}
when ODIN_OS == .OpenBSD {
CLOCKS_PER_SEC :: 100
} else {
CLOCKS_PER_SEC :: 1000000
}
TIME_UTC :: 1
time_t :: distinct i64
clock_t :: long
timespec :: struct {
tv_sec: time_t,
tv_nsec: long,
}
tm :: struct {
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
tm_gmtoff: long,
tm_zone: rawptr,
}
}
+90
View File
@@ -0,0 +1,90 @@
package libc
import "core:c"
char :: c.char // assuming -funsigned-char
schar :: c.schar
short :: c.short
int :: c.int
long :: c.long
longlong :: c.longlong
uchar :: c.uchar
ushort :: c.ushort
uint :: c.uint
ulong :: c.ulong
ulonglong :: c.ulonglong
bool :: c.bool
size_t :: c.size_t
ssize_t :: c.ssize_t
wchar_t :: c.wchar_t
float :: c.float
double :: c.double
int8_t :: c.int8_t
uint8_t :: c.uint8_t
int16_t :: c.int16_t
uint16_t :: c.uint16_t
int32_t :: c.int32_t
uint32_t :: c.uint32_t
int64_t :: c.int64_t
uint64_t :: c.uint64_t
int_least8_t :: c.int_least8_t
uint_least8_t :: c.uint_least8_t
int_least16_t :: c.int_least16_t
uint_least16_t :: c.uint_least16_t
int_least32_t :: c.int_least32_t
uint_least32_t :: c.uint_least32_t
int_least64_t :: c.int_least64_t
uint_least64_t :: c.uint_least64_t
int_fast8_t :: c.int_fast8_t
uint_fast8_t :: c.uint_fast8_t
int_fast16_t :: c.int_fast16_t
uint_fast16_t :: c.uint_fast16_t
int_fast32_t :: c.int_fast32_t
uint_fast32_t :: c.uint_fast32_t
int_fast64_t :: c.int_fast64_t
uint_fast64_t :: c.uint_fast64_t
intptr_t :: c.intptr_t
uintptr_t :: c.uintptr_t
ptrdiff_t :: c.ptrdiff_t
intmax_t :: c.intmax_t
uintmax_t :: c.uintmax_t
// Copy C's rules for type promotion here by forcing the type on the literals.
INT8_MAX :: c.INT8_MAX
INT16_MAX :: c.INT16_MAX
INT32_MAX :: c.INT32_MAX
INT64_MAX :: c.INT64_MAX
UINT8_MAX :: c.UINT8_MAX
UINT16_MAX :: c.UINT16_MAX
UINT32_MAX :: c.UINT32_MAX
UINT64_MAX :: c.UINT64_MAX
INT8_MIN :: c.INT8_MIN
INT16_MIN :: c.INT16_MIN
INT32_MIN :: c.INT32_MIN
INT64_MIN :: c.INT64_MIN
SIZE_MAX :: c.SIZE_MAX
PTRDIFF_MIN :: c.PTRDIFF_MIN
PTRDIFF_MAX :: c.PTRDIFF_MAX
WCHAR_MIN :: c.WCHAR_MIN
WCHAR_MAX :: c.WCHAR_MAX
NULL :: rawptr(uintptr(0))
NDEBUG :: !ODIN_DEBUG
CHAR_BIT :: 8
+23
View File
@@ -0,0 +1,23 @@
package libc
// 7.28 Unicode utilities
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
@(default_calling_convention="c")
foreign libc {
// 7.28.1 Restartable multibyte/wide character conversion functions
mbrtoc16 :: proc(pc16: [^]char16_t, s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---
c16rtomb :: proc(s: ^char, c16: char16_t, ps: ^mbstate_t) -> size_t ---
mbrtoc32 :: proc(pc32: [^]char32_t, s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---
c32rtomb :: proc(s: ^char, c32: char32_t, ps: ^mbstate_t) -> size_t ---
}
char16_t :: uint_least16_t
char32_t :: uint_least32_t
+110
View File
@@ -0,0 +1,110 @@
package libc
// 7.29 Extended multibyte and wide character utilities
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
@(default_calling_convention="c")
foreign libc {
// 7.29.2 Formatted wide character input/output functions
fwprintf :: proc(stream: ^FILE, format: [^]wchar_t, #c_vararg arg: ..any) -> int ---
fwscanf :: proc(stream: ^FILE, format: [^]wchar_t, #c_vararg arg: ..any) -> int ---
swprintf :: proc(stream: ^FILE, n: size_t, format: [^]wchar_t, #c_vararg arg: ..any) -> int ---
swscanf :: proc(s, format: [^]wchar_t, #c_vararg arg: ..any) -> int ---
vfwprintf :: proc(stream: ^FILE, format: [^]wchar_t, arg: va_list) -> int ---
vfwscanf :: proc(stream: ^FILE, format: [^]wchar_t, arg: va_list) -> int ---
vswprintf :: proc(s: [^]wchar_t, n: size_t, format: [^]wchar_t, arg: va_list) -> int ---
vswscanf :: proc(s, format: [^]wchar_t, arg: va_list) -> int ---
vwprintf :: proc(format: [^]wchar_t, arg: va_list) -> int ---
vwscanf :: proc(format: [^]wchar_t, arg: va_list) -> int ---
wprintf :: proc(format: [^]wchar_t, #c_vararg arg: ..any) -> int ---
wscanf :: proc(format: [^]wchar_t, #c_vararg arg: ..any) -> int ---
// 7.29.3 Wide character input/output functions
fwgetc :: proc(stream: ^FILE) -> wint_t ---
fgetws :: proc(s: [^]wchar_t, n: int, stream: ^FILE) -> wchar_t ---
fputwc :: proc(c: wchar_t, stream: ^FILE) -> wint_t ---
fputws :: proc(s: [^]wchar_t, stream: ^FILE) -> int ---
fwide :: proc(stream: ^FILE, mode: int) -> int ---
getwc :: proc(stream: ^FILE) -> wint_t ---
getwchar :: proc() -> wint_t ---
putwc :: proc(c: wchar_t, stream: ^FILE) -> wint_t ---
putwchar :: proc(c: wchar_t) -> wint_t ---
ungetwc :: proc(c: wchar_t, stream: ^FILE) -> wint_t ---
// 7.29.4 General wide string utilities
wcstod :: proc(nptr: [^]wchar_t, endptr: ^[^]wchar_t) -> double ---
wcstof :: proc(nptr: [^]wchar_t, endptr: ^[^]wchar_t) -> float ---
wcstol :: proc(nptr: [^]wchar_t, endptr: ^[^]wchar_t, base: int) -> long ---
wcstoll :: proc(nptr: [^]wchar_t, endptr: ^[^]wchar_t, base: int) -> longlong ---
wcstoul :: proc(nptr: [^]wchar_t, endptr: ^[^]wchar_t, base: int) -> ulong ---
wcstoull :: proc(nptr: [^]wchar_t, endptr: ^[^]wchar_t, base: int) -> ulonglong ---
// 7.29.4.2 Wide string copying functions
wcscpy :: proc(s1, s2: [^]wchar_t) -> [^]wchar_t ---
wcsncpy :: proc(s1, s2: [^]wchar_t, n: size_t) -> [^]wchar_t ---
wmemcpy :: proc(s1, s2: [^]wchar_t, n: size_t) -> [^]wchar_t ---
wmemmove :: proc(s1, s2: [^]wchar_t, n: size_t) -> [^]wchar_t ---
// 7.29.4.3 Wide string concatenation functions
wcscat :: proc(s1, s2: [^]wchar_t) -> [^]wchar_t ---
wcsncat :: proc(s1, s2: [^]wchar_t, n: size_t) -> [^]wchar_t ---
// 7.29.4.4 Wide string comparison functions
wcscmp :: proc(s1, s2: [^]wchar_t) -> int ---
wcscoll :: proc(s1, s2: [^]wchar_t) -> int ---
wcsncmp :: proc(s1, s2: [^]wchar_t, n: size_t) -> int ---
wcsxfrm :: proc(s1, s2: [^]wchar_t, n: size_t) -> size_t ---
wmemcmp :: proc(s1, s2: [^]wchar_t, n: size_t) -> int ---
// 7.29.4.5 Wide string search functions
wcschr :: proc(s: [^]wchar_t, c: wchar_t) -> [^]wchar_t ---
wcscspn :: proc(s1, s2: [^]wchar_t) -> size_t ---
wcspbrk :: proc(s1, s2: [^]wchar_t) -> [^]wchar_t ---
wcsrchr :: proc(s: [^]wchar_t, c: wchar_t) -> [^]wchar_t ---
wcsspn :: proc(s1, s2: [^]wchar_t) -> size_t ---
wcsstr :: proc(s1, s2: [^]wchar_t) -> [^]wchar_t ---
wcstok :: proc(s1, s2: [^]wchar_t, ptr: ^[^]wchar_t) -> [^]wchar_t ---
wmemchr :: proc(s: [^]wchar_t, c: wchar_t, n: size_t) -> [^]wchar_t ---
// 7.29.4.6 Miscellaneous functions
wcslen :: proc(s: [^]wchar_t) -> size_t ---
wmemset :: proc(s: [^]wchar_t, c: wchar_t, n: size_t) -> [^]wchar_t ---
// 7.29.5 Wide character time conversion functions
wcsftime :: proc(s: [^]wchar_t, maxsize: size_t, format: [^]wchar_t, timeptr: ^tm) -> size_t ---
// 7.29.6.1 Single-byte/wide character conversion functions
btowc :: proc(c: int) -> wint_t ---
wctob :: proc(c: wint_t) -> int ---
// 7.29.6.2 Conversion state functions
mbsinit :: proc(ps: ^mbstate_t) -> int ---
// 7.29.6.3 Restartable multibyte/wide character conversion functions
mbrlen :: proc(s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---
mbrtowc :: proc(pwc: [^]wchar_t, s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---
wcrtomb :: proc(s: ^char, wc: wchar_t, ps: ^mbstate_t) -> size_t ---
// 7.29.6.4 Restartable multibyte/wide string conversion functions
mbsrtowcs :: proc(dst: [^]wchar_t, src: ^cstring, len: size_t, ps: ^mbstate_t) -> size_t ---
wcsrtombs :: proc(dst: ^char, src: ^[^]wchar_t, len: size_t, ps: ^mbstate_t) -> size_t ---
}
// Large enough and aligned enough for any wide-spread in-use libc.
mbstate_t :: struct #align 16 { _: [32]char, }
// Odin does not have default argument promotion so the need for a separate type
// here isn't necessary, though make it distinct just to be safe.
wint_t :: distinct wchar_t
// Calculate these values correctly regardless of what type wchar_t actually is.
WINT_MIN :: 0
WINT_MAX :: 1 << (size_of(wint_t) * 8)
WEOF :: ~wint_t(0)
+62
View File
@@ -0,0 +1,62 @@
package libc
// 7.30 Wide character classification and mapping utilities
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
} else when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
when ODIN_OS == .Windows {
wctrans_t :: distinct wchar_t
wctype_t :: distinct ushort
} else when ODIN_OS == .Linux {
wctrans_t :: distinct intptr_t
wctype_t :: distinct ulong
} else when ODIN_OS == .Darwin {
wctrans_t :: distinct int
wctype_t :: distinct u32
} else when ODIN_OS == .OpenBSD {
wctrans_t :: distinct rawptr
wctype_t :: distinct rawptr
} else when ODIN_OS == .FreeBSD {
wctrans_t :: distinct int
wctype_t :: distinct ulong
}
@(default_calling_convention="c")
foreign libc {
// 7.30.2.1 Wide character classification functions
iswalnum :: proc(wc: wint_t) -> int ---
iswalpha :: proc(wc: wint_t) -> int ---
iswblank :: proc(wc: wint_t) -> int ---
iswcntrl :: proc(wc: wint_t) -> int ---
iswdigit :: proc(wc: wint_t) -> int ---
iswgraph :: proc(wc: wint_t) -> int ---
iswlower :: proc(wc: wint_t) -> int ---
iswprint :: proc(wc: wint_t) -> int ---
iswpunct :: proc(wc: wint_t) -> int ---
iswspace :: proc(wc: wint_t) -> int ---
iswupper :: proc(wc: wint_t) -> int ---
iswxdigit :: proc(wc: wint_t) -> int ---
// 7.30.2.2 Extensible wide character classification functions
iswctype :: proc(wc: wint_t, desc: wctype_t) -> int ---
wctype :: proc(property: cstring) -> wctype_t ---
// 7.30.3 Wide character case mapping utilities
towlower :: proc(wc: wint_t) -> wint_t ---
towupper :: proc(wc: wint_t) -> wint_t ---
// 7.30.3.2 Extensible wide character case mapping functions
towctrans :: proc(wc: wint_t, desc: wctrans_t) -> wint_t ---
wctrans :: proc(property: cstring) -> wctrans_t ---
}
+371 -84
View File
@@ -1,22 +1,64 @@
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
*/
// package compress is a collection of utilities to aid with other compression packages
package compress
import "core:io"
import "core:image"
import "core:bytes"
import "core:runtime"
Error :: union {
/*
These settings bound how much compression algorithms will allocate for their output buffer.
If streaming their output, these are unnecessary and will be ignored.
*/
/*
When a decompression routine doesn't stream its output, but writes to a buffer,
we pre-allocate an output buffer to speed up decompression. The default is 1 MiB.
*/
COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 20))
/*
This bounds the maximum a buffer will resize to as needed, or the maximum we'll
pre-allocate if you inform the decompression routine you know the payload size.
For reference, the largest payload size of a GZIP file is 4 GiB.
*/
when size_of(uintptr) == 8 {
/*
For 64-bit platforms, we set the default max buffer size to 4 GiB,
which is GZIP and PKZIP's max payload size.
*/
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 32))
} else {
/*
For 32-bit platforms, we set the default max buffer size to 512 MiB.
*/
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29))
}
Error :: union #shared_nil {
General_Error,
Deflate_Error,
ZLIB_Error,
GZIP_Error,
ZIP_Error,
/*
This is here because png.load will return a this type of error union,
as it may involve an I/O error, a Deflate error, etc.
*/
image.Error,
runtime.Allocator_Error,
}
General_Error :: enum {
None = 0,
File_Not_Found,
Cannot_Open_File,
File_Too_Short,
@@ -26,9 +68,16 @@ General_Error :: enum {
Checksum_Failed,
Incompatible_Options,
Unimplemented,
/*
Memory errors
*/
Allocation_Failed,
Resize_Failed,
}
GZIP_Error :: enum {
None = 0,
Invalid_GZIP_Signature,
Reserved_Flag_Set,
Invalid_Extra_Data,
@@ -36,9 +85,24 @@ GZIP_Error :: enum {
Comment_Too_Long,
Payload_Length_Invalid,
Payload_CRC_Invalid,
/*
GZIP's payload can be a maximum of max(u32le), or 4 GiB.
If you tell it you expect it to contain more, that's obviously an error.
*/
Payload_Size_Exceeds_Max_Payload,
/*
For buffered instead of streamed output, the payload size can't exceed
the max set by the `COMPRESS_OUTPUT_ALLOCATE_MAX` switch in compress/common.odin.
You can tweak this setting using `-define:COMPRESS_OUTPUT_ALLOCATE_MAX=size_in_bytes`
*/
Output_Exceeds_COMPRESS_OUTPUT_ALLOCATE_MAX,
}
ZIP_Error :: enum {
None = 0,
Invalid_ZIP_File_Signature,
Unexpected_Signature,
Insert_Next_Disk,
@@ -46,6 +110,7 @@ ZIP_Error :: enum {
}
ZLIB_Error :: enum {
None = 0,
Unsupported_Window_Size,
FDICT_Unsupported,
Unsupported_Compression_Level,
@@ -53,6 +118,7 @@ ZLIB_Error :: enum {
}
Deflate_Error :: enum {
None = 0,
Huffman_Bad_Sizes,
Huffman_Bad_Code_Lengths,
Inflate_Error,
@@ -62,135 +128,356 @@ Deflate_Error :: enum {
BType_3,
}
// General context for ZLIB, LZW, etc.
Context :: struct {
code_buffer: u32,
num_bits: i8,
// General I/O context for ZLIB, LZW, etc.
Context_Memory_Input :: struct #packed {
input_data: []u8,
output: ^bytes.Buffer,
bytes_written: i64,
code_buffer: u64,
num_bits: u64,
/*
num_bits will be set to -100 if the buffer is malformed
If we know the data size, we can optimize the reads and writes.
*/
eof: b8,
input: io.Stream,
output: io.Stream,
bytes_written: i64,
// Used to update hash as we write instead of all at once
rolling_hash: u32,
// Sliding window buffer. Size must be a power of two.
window_size: i64,
last: ^[dynamic]byte,
size_packed: i64,
size_unpacked: i64,
}
when size_of(rawptr) == 8 {
#assert(size_of(Context_Memory_Input) == 64)
} else {
// e.g. `-target:windows_i386`
#assert(size_of(Context_Memory_Input) == 52)
}
// Stream helpers
/*
TODO: These need to be optimized.
Context_Stream_Input :: struct #packed {
input_data: []u8,
input: io.Stream,
output: ^bytes.Buffer,
bytes_written: i64,
Streams should really only check if a certain method is available once, perhaps even during setup.
code_buffer: u64,
num_bits: u64,
/*
If we know the data size, we can optimize the reads and writes.
*/
size_packed: i64,
size_unpacked: i64,
/*
Flags:
`input_fully_in_memory`
true = This tells us we read input from `input_data` exclusively. [] = EOF.
false = Try to refill `input_data` from the `input` stream.
*/
input_fully_in_memory: b8,
padding: [1]u8,
}
/*
TODO: The stream versions should really only check if a certain method is available once, perhaps even during setup.
Bit and byte readers may be merged so that reading bytes will grab them from the bit buffer first.
This simplifies end-of-stream handling where bits may be left in the bit buffer.
*/
read_data :: #force_inline proc(c: ^Context, $T: typeid) -> (res: T, err: io.Error) {
b := make([]u8, size_of(T), context.temp_allocator);
r, e1 := io.to_reader(c.input);
_, e2 := io.read(r, b);
if !e1 || e2 != .None {
return T{}, e2;
input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Error) {
return i64(len(z.input_data)), nil
}
input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Error) {
return io.size(z.input), nil
}
input_size :: proc{input_size_from_memory, input_size_from_stream}
@(optimization_mode="speed")
read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int) -> (res: []u8, err: io.Error) {
#no_bounds_check {
if len(z.input_data) >= size {
res = z.input_data[:size]
z.input_data = z.input_data[size:]
return res, .None
}
}
res = (^T)(raw_data(b))^;
return res, .None;
if len(z.input_data) == 0 {
return []u8{}, .EOF
} else {
return []u8{}, .Short_Buffer
}
}
read_u8 :: #force_inline proc(z: ^Context) -> (res: u8, err: io.Error) {
return read_data(z, u8);
@(optimization_mode="speed")
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
b := make([]u8, size, context.temp_allocator)
_, e := z.input->impl_read(b[:])
if e == .None {
return b, .None
}
return []u8{}, e
}
peek_data :: #force_inline proc(c: ^Context, $T: typeid) -> (res: T, err: io.Error) {
read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
@(optimization_mode="speed")
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
b, e := read_slice(z, size_of(T))
if e == .None {
return (^T)(&b[0])^, .None
}
return T{}, e
}
@(optimization_mode="speed")
read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8, err: io.Error) {
#no_bounds_check {
if len(z.input_data) >= 1 {
res = z.input_data[0]
z.input_data = z.input_data[1:]
return res, .None
}
}
return 0, .EOF
}
@(optimization_mode="speed")
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
b, e := read_slice_from_stream(z, 1)
if e == .None {
return b[0], .None
}
return 0, e
}
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
/*
You would typically only use this at the end of Inflate, to drain bits from the code buffer
preferentially.
*/
@(optimization_mode="speed")
read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: io.Error) {
if z.num_bits >= 8 {
res = u8(read_bits_no_refill_lsb(z, 8))
} else {
size, _ := input_size(z)
if size > 0 {
res, err = read_u8(z)
} else {
err = .EOF
}
}
return
}
@(optimization_mode="speed")
peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T)
#no_bounds_check {
if len(z.input_data) >= size {
buf := z.input_data[:size]
return (^T)(&buf[0])^, .None
}
}
if len(z.input_data) == 0 {
return T{}, .EOF
} else {
return T{}, .Short_Buffer
}
}
@(optimization_mode="speed")
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T)
// Get current position to read from.
curr, e1 := c.input->impl_seek(0, .Current);
curr, e1 := z.input->impl_seek(0, .Current)
if e1 != .None {
return T{}, e1;
return T{}, e1
}
r, e2 := io.to_reader_at(c.input);
r, e2 := io.to_reader_at(z.input)
if !e2 {
return T{}, .Empty;
return T{}, .Empty
}
b := make([]u8, size_of(T), context.temp_allocator);
_, e3 := io.read_at(r, b, curr);
when size <= 128 {
b: [size]u8
} else {
b := make([]u8, size, context.temp_allocator)
}
_, e3 := io.read_at(r, b[:], curr)
if e3 != .None {
return T{}, .Empty;
return T{}, .Empty
}
res = (^T)(raw_data(b))^;
return res, .None;
res = (^T)(&b[0])^
return res, .None
}
peek_data :: proc{peek_data_from_memory, peek_data_from_stream}
// Sliding window read back
peek_back_byte :: proc(c: ^Context, offset: i64) -> (res: u8, err: io.Error) {
@(optimization_mode="speed")
peek_back_byte :: #force_inline proc(z: ^$C, offset: i64) -> (res: u8, err: io.Error) {
// Look back into the sliding window.
return c.last[offset % c.window_size], .None;
return z.output.buf[z.bytes_written - offset], .None
}
// Generalized bit reader LSB
refill_lsb :: proc(z: ^Context, width := i8(24)) {
@(optimization_mode="speed")
refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width := i8(48)) {
refill := u64(width)
b := u64(0)
if z.num_bits > refill {
return
}
for {
if z.num_bits > width {
break;
if len(z.input_data) != 0 {
b = u64(z.input_data[0])
z.input_data = z.input_data[1:]
} else {
b = 0
}
if z.code_buffer == 0 && z.num_bits == -1 {
z.num_bits = 0;
z.code_buffer |= b << u8(z.num_bits)
z.num_bits += 8
if z.num_bits > refill {
break
}
}
}
// Generalized bit reader LSB
@(optimization_mode="speed")
refill_lsb_from_stream :: proc(z: ^Context_Stream_Input, width := i8(24)) {
refill := u64(width)
for {
if z.num_bits > refill {
break
}
if z.code_buffer == 0 && z.num_bits > 63 {
z.num_bits = 0
}
if z.code_buffer >= 1 << uint(z.num_bits) {
// Code buffer is malformed.
z.num_bits = -100;
return;
z.num_bits = max(u64)
return
}
c, err := read_u8(z);
b, err := read_u8(z)
if err != .None {
// This is fine at the end of the file.
z.num_bits = -42;
z.eof = true;
return;
return
}
z.code_buffer |= (u32(c) << u8(z.num_bits));
z.num_bits += 8;
z.code_buffer |= (u64(b) << u8(z.num_bits))
z.num_bits += 8
}
}
consume_bits_lsb :: #force_inline proc(z: ^Context, width: u8) {
z.code_buffer >>= width;
z.num_bits -= i8(width);
refill_lsb :: proc{refill_lsb_from_memory, refill_lsb_from_stream}
@(optimization_mode="speed")
consume_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) {
z.code_buffer >>= width
z.num_bits -= u64(width)
}
peek_bits_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
if z.num_bits < i8(width) {
refill_lsb(z);
@(optimization_mode="speed")
consume_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) {
z.code_buffer >>= width
z.num_bits -= u64(width)
}
consume_bits_lsb :: proc{consume_bits_lsb_from_memory, consume_bits_lsb_from_stream}
@(optimization_mode="speed")
peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
if z.num_bits < u64(width) {
refill_lsb(z)
}
// assert(z.num_bits >= i8(width));
return z.code_buffer & ~(~u32(0) << width);
return u32(z.code_buffer & ~(~u64(0) << width))
}
peek_bits_no_refill_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
assert(z.num_bits >= i8(width));
return z.code_buffer & ~(~u32(0) << width);
@(optimization_mode="speed")
peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
if z.num_bits < u64(width) {
refill_lsb(z)
}
return u32(z.code_buffer & ~(~u64(0) << width))
}
read_bits_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
k := peek_bits_lsb(z, width);
consume_bits_lsb(z, width);
return k;
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
@(optimization_mode="speed")
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width))
return u32(z.code_buffer & ~(~u64(0) << width))
}
read_bits_no_refill_lsb :: #force_inline proc(z: ^Context, width: u8) -> u32 {
k := peek_bits_no_refill_lsb(z, width);
consume_bits_lsb(z, width);
return k;
@(optimization_mode="speed")
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width))
return u32(z.code_buffer & ~(~u64(0) << width))
}
discard_to_next_byte_lsb :: proc(z: ^Context) {
discard := u8(z.num_bits & 7);
consume_bits_lsb(z, discard);
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
@(optimization_mode="speed")
read_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
k := #force_inline peek_bits_lsb(z, width)
#force_inline consume_bits_lsb(z, width)
return k
}
@(optimization_mode="speed")
read_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
k := peek_bits_lsb(z, width)
consume_bits_lsb(z, width)
return k
}
read_bits_lsb :: proc{read_bits_lsb_from_memory, read_bits_lsb_from_stream}
@(optimization_mode="speed")
read_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
k := #force_inline peek_bits_no_refill_lsb(z, width)
#force_inline consume_bits_lsb(z, width)
return k
}
@(optimization_mode="speed")
read_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
k := peek_bits_no_refill_lsb(z, width)
consume_bits_lsb(z, width)
return k
}
read_bits_no_refill_lsb :: proc{read_bits_no_refill_lsb_from_memory, read_bits_no_refill_lsb_from_stream}
@(optimization_mode="speed")
discard_to_next_byte_lsb_from_memory :: proc(z: ^Context_Memory_Input) {
discard := u8(z.num_bits & 7)
#force_inline consume_bits_lsb(z, discard)
}
@(optimization_mode="speed")
discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
discard := u8(z.num_bits & 7)
consume_bits_lsb(z, discard)
}
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}
+45 -26
View File
@@ -1,9 +1,21 @@
//+ignore
package gzip
import "core:compress/gzip"
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
Ginger Bill: Cosmetic changes.
A small GZIP implementation as an example.
*/
import "core:bytes"
import "core:os"
import "core:compress"
import "core:fmt"
// Small GZIP file with fextra, fname and fcomment present.
@private
@@ -16,55 +28,62 @@ TEST: []u8 = {
0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
};
}
main :: proc() {
// Set up output buffer.
buf: bytes.Buffer;
defer bytes.buffer_destroy(&buf);
buf := bytes.Buffer{}
stdout :: proc(s: string) {
os.write_string(os.stdout, s);
os.write_string(os.stdout, s)
}
stderr :: proc(s: string) {
os.write_string(os.stderr, s);
os.write_string(os.stderr, s)
}
args := os.args;
args := os.args
if len(args) < 2 {
stderr("No input file specified.\n");
err := gzip.load(TEST, &buf);
if err != nil {
stdout("Displaying test vector: ");
stdout(bytes.buffer_to_string(&buf));
stdout("\n");
stderr("No input file specified.\n")
err := load(slice=TEST, buf=&buf, known_gzip_size=len(TEST))
if err == nil {
stdout("Displaying test vector: ")
stdout(bytes.buffer_to_string(&buf))
stdout("\n")
} else {
fmt.printf("gzip.load returned %v\n", err)
}
bytes.buffer_destroy(&buf)
os.exit(0)
}
// The rest are all files.
args = args[1:];
err: gzip.Error;
args = args[1:]
err: Error
for file in args {
if file == "-" {
// Read from stdin
s := os.stream_from_handle(os.stdin);
err = gzip.load(s, &buf);
s := os.stream_from_handle(os.stdin)
ctx := &compress.Context_Stream_Input{
input = s,
}
err = load(ctx, &buf)
} else {
err = gzip.load(file, &buf);
err = load(file, &buf)
}
if err != nil {
if err != E_General.File_Not_Found {
stderr("File not found: ");
stderr(file);
stderr("\n");
os.exit(1);
stderr("File not found: ")
stderr(file)
stderr("\n")
os.exit(1)
}
stderr("GZIP returned an error.\n");
os.exit(2);
stderr("GZIP returned an error.\n")
bytes.buffer_destroy(&buf)
os.exit(2)
}
stdout(bytes.buffer_to_string(&buf));
stdout(bytes.buffer_to_string(&buf))
}
os.exit(0);
bytes.buffer_destroy(&buf)
}
+173 -115
View File
@@ -1,5 +1,19 @@
package gzip
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
This package implements support for the GZIP file format v4.3,
as specified in RFC 1952.
It is implemented in such a way that it lends itself naturally
to be the input to a complementary TAR implementation.
*/
import "core:compress/zlib"
import "core:compress"
import "core:os"
@@ -7,16 +21,6 @@ import "core:io"
import "core:bytes"
import "core:hash"
/*
This package implements support for the GZIP file format v4.3,
as specified in RFC 1952.
It is implemented in such a way that it lends itself naturally
to be the input to a complementary TAR implementation.
*/
Magic :: enum u16le {
GZIP = 0x8b << 8 | 0x1f,
}
@@ -29,7 +33,7 @@ Header :: struct #packed {
xfl: Compression_Flags,
os: OS,
}
#assert(size_of(Header) == 10);
#assert(size_of(Header) == 10)
Header_Flag :: enum u8 {
// Order is important
@@ -42,7 +46,7 @@ Header_Flag :: enum u8 {
reserved_2 = 6,
reserved_3 = 7,
}
Header_Flags :: distinct bit_set[Header_Flag; u8];
Header_Flags :: distinct bit_set[Header_Flag; u8]
OS :: enum u8 {
FAT = 0,
@@ -62,7 +66,8 @@ OS :: enum u8 {
_Unknown = 14,
Unknown = 255,
}
OS_Name :: #partial [OS]string{
OS_Name :: #sparse[OS]string{
._Unknown = "",
.FAT = "FAT",
.Amiga = "Amiga",
.VMS = "VMS/OpenVMS",
@@ -78,7 +83,7 @@ OS_Name :: #partial [OS]string{
.QDOS = "QDOS",
.Acorn_RISCOS = "Acorn RISCOS",
.Unknown = "Unknown",
};
}
Compression :: enum u8 {
DEFLATE = 8,
@@ -89,60 +94,77 @@ Compression_Flags :: enum u8 {
Fastest_Compression = 4,
}
Error :: compress.Error;
E_General :: compress.General_Error;
E_GZIP :: compress.GZIP_Error;
E_ZLIB :: compress.ZLIB_Error;
E_Deflate :: compress.Deflate_Error;
Error :: compress.Error
E_General :: compress.General_Error
E_GZIP :: compress.GZIP_Error
E_ZLIB :: compress.ZLIB_Error
E_Deflate :: compress.Deflate_Error
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, allocator := context.allocator) -> (err: Error) {
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
r := bytes.Reader{};
bytes.reader_init(&r, slice);
stream := bytes.reader_to_stream(&r);
load :: proc{load_from_slice, load_from_file, load_from_context}
err = load_from_stream(stream, buf, allocator);
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
context.allocator = allocator
return err;
}
data, ok := os.read_entire_file(filename)
defer delete(data)
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, allocator := context.allocator) -> (err: Error) {
data, ok := os.read_entire_file(filename, allocator);
defer delete(data);
err = E_General.File_Not_Found;
err = E_General.File_Not_Found
if ok {
err = load_from_slice(data, buf, allocator);
err = load_from_slice(data, buf, len(data), expected_output_size)
}
return;
return
}
load_from_stream :: proc(stream: io.Stream, buf: ^bytes.Buffer, allocator := context.allocator) -> (err: Error) {
ctx := compress.Context{
input = stream,
};
buf := buf;
ws := bytes.buffer_to_stream(buf);
ctx.output = ws;
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
buf := buf
header, e := compress.read_data(&ctx, Header);
if e != .None {
return E_General.File_Too_Short;
z := &compress.Context_Memory_Input{
input_data = slice,
output = buf,
}
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
}
load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
context.allocator = allocator
buf := buf
expected_output_size := expected_output_size
input_data_consumed := 0
z.output = buf
if i64(expected_output_size) > i64(GZIP_MAX_PAYLOAD_SIZE) {
return E_GZIP.Payload_Size_Exceeds_Max_Payload
}
if expected_output_size > compress.COMPRESS_OUTPUT_ALLOCATE_MAX {
return E_GZIP.Output_Exceeds_COMPRESS_OUTPUT_ALLOCATE_MAX
}
b: []u8
header, e := compress.read_data(z, Header)
if e != .None {
return E_General.File_Too_Short
}
input_data_consumed += size_of(Header)
if header.magic != .GZIP {
return E_GZIP.Invalid_GZIP_Signature;
return E_GZIP.Invalid_GZIP_Signature
}
if header.compression_method != .DEFLATE {
return E_General.Unknown_Compression_Method;
return E_General.Unknown_Compression_Method
}
if header.os >= ._Unknown {
header.os = .Unknown;
header.os = .Unknown
}
if .reserved_1 in header.flags || .reserved_2 in header.flags || .reserved_3 in header.flags {
return E_GZIP.Reserved_Flag_Set;
return E_GZIP.Reserved_Flag_Set
}
// printf("signature: %v\n", header.magic);
@@ -153,80 +175,84 @@ load_from_stream :: proc(stream: io.Stream, buf: ^bytes.Buffer, allocator := con
// printf("os: %v\n", OS_Name[header.os]);
if .extra in header.flags {
xlen, e_extra := compress.read_data(&ctx, u16le);
xlen, e_extra := compress.read_data(z, u16le)
input_data_consumed += 2
if e_extra != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
// printf("Extra data present (%v bytes)\n", xlen);
if xlen < 4 {
// Minimum length is 2 for ID + 2 for a field length, if set to zero.
return E_GZIP.Invalid_Extra_Data;
return E_GZIP.Invalid_Extra_Data
}
field_id: [2]u8;
field_length: u16le;
field_error: io.Error;
field_id: [2]u8
field_length: u16le
field_error: io.Error
for xlen >= 4 {
// println("Parsing Extra field(s).");
field_id, field_error = compress.read_data(&ctx, [2]u8);
field_id, field_error = compress.read_data(z, [2]u8)
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
xlen -= 2;
xlen -= 2
input_data_consumed += 2
field_length, field_error = compress.read_data(&ctx, u16le);
field_length, field_error = compress.read_data(z, u16le)
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
xlen -= 2;
xlen -= 2
input_data_consumed += 2
if xlen <= 0 {
// We're not going to try and recover by scanning for a ZLIB header.
// Who knows what else is wrong with this file.
return E_GZIP.Invalid_Extra_Data;
return E_GZIP.Invalid_Extra_Data
}
// printf(" Field \"%v\" of length %v found: ", string(field_id[:]), field_length);
if field_length > 0 {
field_data := make([]u8, field_length, context.temp_allocator);
_, field_error = ctx.input->impl_read(field_data);
b, field_error = compress.read_slice(z, int(field_length))
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
xlen -= field_length;
xlen -= field_length
input_data_consumed += int(field_length)
// printf("%v\n", string(field_data));
}
}
if xlen != 0 {
return E_GZIP.Invalid_Extra_Data;
return E_GZIP.Invalid_Extra_Data
}
}
}
if .name in header.flags {
// Should be enough.
name: [1024]u8;
b: [1]u8;
i := 0;
name_error: io.Error;
name: [1024]u8
i := 0
name_error: io.Error
for i < len(name) {
_, name_error = ctx.input->impl_read(b[:]);
b, name_error = compress.read_slice(z, 1)
if name_error != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
if b == 0 {
break;
input_data_consumed += 1
if b[0] == 0 {
break
}
name[i] = b[0];
i += 1;
name[i] = b[0]
i += 1
if i >= len(name) {
return E_GZIP.Original_Name_Too_Long;
return E_GZIP.Original_Name_Too_Long
}
}
// printf("Original filename: %v\n", string(name[:i]));
@@ -234,34 +260,34 @@ load_from_stream :: proc(stream: io.Stream, buf: ^bytes.Buffer, allocator := con
if .comment in header.flags {
// Should be enough.
comment: [1024]u8;
b: [1]u8;
i := 0;
comment_error: io.Error;
comment: [1024]u8
i := 0
comment_error: io.Error
for i < len(comment) {
_, comment_error = ctx.input->impl_read(b[:]);
b, comment_error = compress.read_slice(z, 1)
if comment_error != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
if b == 0 {
break;
input_data_consumed += 1
if b[0] == 0 {
break
}
comment[i] = b[0];
i += 1;
comment[i] = b[0]
i += 1
if i >= len(comment) {
return E_GZIP.Comment_Too_Long;
return E_GZIP.Comment_Too_Long
}
}
// printf("Comment: %v\n", string(comment[:i]));
}
if .header_crc in header.flags {
crc16: [2]u8;
crc_error: io.Error;
_, crc_error = ctx.input->impl_read(crc16[:]);
crc_error: io.Error
_, crc_error = compress.read_slice(z, 2)
input_data_consumed += 2
if crc_error != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
/*
We don't actually check the CRC16 (lower 2 bytes of CRC32 of header data until the CRC field).
@@ -272,42 +298,74 @@ load_from_stream :: proc(stream: io.Stream, buf: ^bytes.Buffer, allocator := con
/*
We should have arrived at the ZLIB payload.
*/
payload_u32le: u32le
zlib_error := zlib.inflate_raw(&ctx);
// fmt.printf("known_gzip_size: %v | expected_output_size: %v\n", known_gzip_size, expected_output_size);
// fmt.printf("ZLIB returned: %v\n", zlib_error);
if expected_output_size > -1 {
/*
We already checked that it's not larger than the output buffer max,
or GZIP length field's max.
if zlib_error != nil {
return zlib_error;
We'll just pass it on to `zlib.inflate_raw`;
*/
} else {
/*
If we know the size of the GZIP file *and* it is fully in memory,
then we can peek at the unpacked size at the end.
We'll still want to ensure there's capacity left in the output buffer when we write, of course.
*/
if known_gzip_size > -1 {
offset := i64(known_gzip_size - input_data_consumed - 4)
size, _ := compress.input_size(z)
if size >= offset + 4 {
length_bytes := z.input_data[offset:][:4]
payload_u32le = (^u32le)(&length_bytes[0])^
expected_output_size = int(payload_u32le)
}
} else {
/*
TODO(Jeroen): When reading a GZIP from a stream, check if impl_seek is present.
If so, we can seek to the end, grab the size from the footer, and seek back to payload start.
*/
}
}
// fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size);
zlib_error := zlib.inflate_raw(z=z, expected_output_size=expected_output_size)
if zlib_error != nil {
return zlib_error
}
/*
Read CRC32 using the ctx bit reader because zlib may leave bytes in there.
*/
compress.discard_to_next_byte_lsb(&ctx);
compress.discard_to_next_byte_lsb(z)
payload_crc_b: [4]u8;
payload_len_b: [4]u8;
for i in 0..3 {
payload_crc_b[i] = u8(compress.read_bits_lsb(&ctx, 8));
footer_error: io.Error
payload_crc_b: [4]u8
for _, i in payload_crc_b {
payload_crc_b[i], footer_error = compress.read_u8_prefer_code_buffer_lsb(z)
}
payload_crc := transmute(u32le)payload_crc_b;
for i in 0..3 {
payload_len_b[i] = u8(compress.read_bits_lsb(&ctx, 8));
}
payload_len := int(transmute(u32le)payload_len_b);
payload := bytes.buffer_to_bytes(buf);
crc32 := u32le(hash.crc32(payload));
payload_crc := transmute(u32le)payload_crc_b
payload := bytes.buffer_to_bytes(buf)
crc32 := u32le(hash.crc32(payload))
if crc32 != payload_crc {
return E_GZIP.Payload_CRC_Invalid;
return E_GZIP.Payload_CRC_Invalid
}
if len(payload) != payload_len {
return E_GZIP.Payload_Length_Invalid;
payload_len_b: [4]u8
for _, i in payload_len_b {
payload_len_b[i], footer_error = compress.read_u8_prefer_code_buffer_lsb(z)
}
return nil;
payload_len := transmute(u32le)payload_len_b
if len(payload) != int(payload_len) {
return E_GZIP.Payload_Length_Invalid
}
return nil
}
load :: proc{load_from_file, load_from_slice, load_from_stream};
+148
View File
@@ -0,0 +1,148 @@
/*
This file was generated, so don't edit this by hand.
Transliterated from https://github.com/Ed-von-Schleck/shoco/blob/master/shoco_model.h,
which is an English word model.
*/
// package shoco is an implementation of the shoco short string compressor
package shoco
DEFAULT_MODEL :: Shoco_Model {
min_char = 39,
max_char = 122,
characters_by_id = {
'e', 'a', 'i', 'o', 't', 'h', 'n', 'r', 's', 'l', 'u', 'c', 'w', 'm', 'd', 'b', 'p', 'f', 'g', 'v', 'y', 'k', '-', 'H', 'M', 'T', '\'', 'B', 'x', 'I', 'W', 'L',
},
ids_by_character = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 23, 29, -1, -1, 31, 24, -1, -1, -1, -1, -1, -1, 25, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 15, 11, 14, 0, 17, 18, 5, 2, -1, 21, 9, 13, 6, 3, 16, -1, 7, 8, 4, 10, 19, 12, 28, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
},
successors_by_bigram = {
7, 4, 12, -1, 6, -1, 1, 0, 3, 5, -1, 9, -1, 8, 2, -1, 15, 14, -1, 10, 11, -1, -1, -1, -1, -1, -1, -1, 13, -1, -1, -1,
1, -1, 6, -1, 1, -1, 0, 3, 2, 4, 15, 11, -1, 9, 5, 10, 13, -1, 12, 8, 7, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 11, -1, 4, 2, -1, 0, 8, 1, 5, -1, 6, -1, 3, 7, 15, -1, 12, 10, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 14, 7, 5, -1, 1, 2, 8, 9, 0, 15, 6, 4, 11, -1, 12, 3, -1, 10, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 4, 3, 1, 5, 0, -1, 6, 10, 9, 7, 12, 11, -1, -1, -1, -1, 13, -1, -1, 8, -1, 15, -1, -1, -1, 14, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, -1, -1, 5, 9, 10, 6, -1, -1, 8, 15, 11, -1, 14, -1, -1, 7, -1, 13, -1, -1, -1, 12, -1, -1, -1, -1, -1,
2, 8, 7, 4, 3, -1, 9, -1, 6, 11, -1, 5, -1, -1, 0, -1, -1, 14, 1, 15, 10, 12, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1,
0, 3, 1, 2, 6, -1, 9, 8, 4, 12, 13, 10, -1, 11, 7, -1, -1, 15, 14, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 6, 3, 4, 1, 2, -1, -1, 5, 10, 7, 9, 11, 12, -1, -1, 8, 14, -1, -1, 15, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 6, 2, 5, 9, -1, -1, -1, 10, 1, 8, -1, 12, 14, 4, -1, 15, 7, -1, 13, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8, 10, 9, 15, 1, -1, 4, 0, 3, 2, -1, 6, -1, 12, 11, 13, 7, 14, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 3, 6, 0, 4, 2, -1, 7, 13, 8, 9, 11, -1, -1, 15, -1, -1, -1, -1, -1, 10, 5, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 0, 1, 4, -1, 2, 5, 6, 7, 8, -1, 14, -1, -1, 9, 15, -1, 12, -1, -1, -1, 10, 11, -1, -1, -1, 13, -1, -1, -1, -1, -1,
0, 1, 3, 2, 15, -1, 12, -1, 7, 14, 4, -1, -1, 9, -1, 8, 5, 10, -1, -1, 6, -1, 13, -1, -1, -1, 11, -1, -1, -1, -1, -1,
0, 3, 1, 2, -1, -1, 12, 6, 4, 9, 7, -1, -1, 14, 8, -1, -1, 15, 11, 13, 5, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 5, 7, 2, 10, 13, -1, 6, 8, 1, 3, -1, -1, 14, 15, 11, -1, -1, -1, 12, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 2, 6, 3, 7, 10, -1, 1, 9, 4, 8, -1, -1, 15, -1, 12, 5, -1, -1, -1, 11, -1, 13, -1, -1, -1, 14, -1, -1, -1, -1, -1,
1, 3, 4, 0, 7, -1, 12, 2, 11, 8, 6, 13, -1, -1, -1, -1, -1, 5, -1, -1, 10, 15, 9, -1, -1, -1, 14, -1, -1, -1, -1, -1,
1, 3, 5, 2, 13, 0, 9, 4, 7, 6, 8, -1, -1, 15, -1, 11, -1, -1, 10, -1, 14, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 2, 1, 3, -1, -1, -1, 6, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 11, 4, 0, 3, -1, 13, 12, 2, 7, -1, -1, 15, 10, 5, 8, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, 6, -1, -1, -1, -1, -1,
0, 9, 2, 14, 15, 4, 1, 13, 3, 5, -1, -1, 10, -1, -1, -1, -1, 6, 12, -1, 7, -1, 8, -1, -1, -1, 11, -1, -1, -1, -1, -1,
-1, 2, 14, -1, 1, 5, 8, 7, 4, 12, -1, 6, 9, 11, 13, 3, 10, 15, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 3, 2, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 3, 1, 5, -1, -1, -1, 0, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 8, 4, 1, -1, 0, -1, 6, -1, -1, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1,
12, 5, -1, -1, 1, -1, -1, 7, 0, 3, -1, 2, -1, 4, 6, -1, -1, -1, -1, 8, -1, -1, 15, -1, 13, 9, -1, -1, -1, -1, -1, 11,
1, 3, 2, 4, -1, -1, -1, 5, -1, 7, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1,
5, 3, 4, 12, 1, 6, -1, -1, -1, -1, 8, 2, -1, -1, -1, -1, 0, 9, -1, -1, 11, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 0, -1, 1, 12, 3, -1, -1, -1, -1, 5, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, 6, -1, 10,
2, 3, 1, 4, -1, 0, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1,
5, 1, 3, 0, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 9, -1, -1, 6, -1, 7,
},
successors_reversed = {
's', 't', 'c', 'l', 'm', 'a', 'd', 'r', 'v', 'T', 'A', 'L', 'e', 'M', 'Y', '-',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'-', 't', 'a', 'b', 's', 'h', 'c', 'r', 'n', 'w', 'p', 'm', 'l', 'd', 'i', 'f',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'u', 'e', 'i', 'a', 'o', 'r', 'y', 'l', 'I', 'E', 'R', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'e', 'a', 'o', 'i', 'u', 'A', 'y', 'E', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
't', 'n', 'f', 's', '\'', 'm', 'I', 'N', 'A', 'E', 'L', 'Z', 'r', 'V', 'R', 'C',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'o', 'a', 'y', 'i', 'u', 'e', 'I', 'L', 'D', '\'', 'E', 'Y', '\x00', '\x00', '\x00', '\x00',
'r', 'i', 'y', 'a', 'e', 'o', 'u', 'Y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'h', 'o', 'e', 'E', 'i', 'u', 'r', 'w', 'a', 'H', 'y', 'R', 'Z', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'h', 'i', 'e', 'a', 'o', 'r', 'I', 'y', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'n', 't', 's', 'r', 'l', 'd', 'i', 'y', 'v', 'm', 'b', 'c', 'g', 'p', 'k', 'u',
'e', 'l', 'o', 'u', 'y', 'a', 'r', 'i', 's', 'j', 't', 'b', 'v', 'h', 'm', 'd',
'o', 'e', 'h', 'a', 't', 'k', 'i', 'r', 'l', 'u', 'y', 'c', 'q', 's', '-', 'd',
'e', 'i', 'o', 'a', 's', 'y', 'r', 'u', 'd', 'l', '-', 'g', 'n', 'v', 'm', 'f',
'r', 'n', 'd', 's', 'a', 'l', 't', 'e', 'm', 'c', 'v', 'y', 'i', 'x', 'f', 'p',
'o', 'e', 'r', 'a', 'i', 'f', 'u', 't', 'l', '-', 'y', 's', 'n', 'c', '\'', 'k',
'h', 'e', 'o', 'a', 'r', 'i', 'l', 's', 'u', 'n', 'g', 'b', '-', 't', 'y', 'm',
'e', 'a', 'i', 'o', 't', 'r', 'u', 'y', 'm', 's', 'l', 'b', '\'', '-', 'f', 'd',
'n', 's', 't', 'm', 'o', 'l', 'c', 'd', 'r', 'e', 'g', 'a', 'f', 'v', 'z', 'b',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'e', 'n', 'i', 's', 'h', 'l', 'f', 'y', '-', 'a', 'w', '\'', 'g', 'r', 'o', 't',
'e', 'l', 'i', 'y', 'd', 'o', 'a', 'f', 'u', 't', 's', 'k', 'w', 'v', 'm', 'p',
'e', 'a', 'o', 'i', 'u', 'p', 'y', 's', 'b', 'm', 'f', '\'', 'n', '-', 'l', 't',
'd', 'g', 'e', 't', 'o', 'c', 's', 'i', 'a', 'n', 'y', 'l', 'k', '\'', 'f', 'v',
'u', 'n', 'r', 'f', 'm', 't', 'w', 'o', 's', 'l', 'v', 'd', 'p', 'k', 'i', 'c',
'e', 'r', 'a', 'o', 'l', 'p', 'i', 't', 'u', 's', 'h', 'y', 'b', '-', '\'', 'm',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'e', 'i', 'o', 'a', 's', 'y', 't', 'd', 'r', 'n', 'c', 'm', 'l', 'u', 'g', 'f',
'e', 't', 'h', 'i', 'o', 's', 'a', 'u', 'p', 'c', 'l', 'w', 'm', 'k', 'f', 'y',
'h', 'o', 'e', 'i', 'a', 't', 'r', 'u', 'y', 'l', 's', 'w', 'c', 'f', '\'', '-',
'r', 't', 'l', 's', 'n', 'g', 'c', 'p', 'e', 'i', 'a', 'd', 'm', 'b', 'f', 'o',
'e', 'i', 'a', 'o', 'y', 'u', 'r', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'a', 'i', 'h', 'e', 'o', 'n', 'r', 's', 'l', 'd', 'k', '-', 'f', '\'', 'c', 'b',
'p', 't', 'c', 'a', 'i', 'e', 'h', 'q', 'u', 'f', '-', 'y', 'o', '\x00', '\x00', '\x00',
'o', 'e', 's', 't', 'i', 'd', '\'', 'l', 'b', '-', 'm', 'a', 'r', 'n', 'p', 'w',
},
character_count = 32,
successor_count = 16,
max_successor_n = 7,
packs = {
{ 0x80000000, 1, 2, { 26, 24, 24, 24, 24, 24, 24, 24 }, { 15, 3, 0, 0, 0, 0, 0, 0 }, 0xc0, 0x80 },
{ 0xc0000000, 2, 4, { 25, 22, 19, 16, 16, 16, 16, 16 }, { 15, 7, 7, 7, 0, 0, 0, 0 }, 0xe0, 0xc0 },
{ 0xe0000000, 4, 8, { 23, 19, 15, 11, 8, 5, 2, 0 }, { 31, 15, 15, 15, 7, 7, 7, 3 }, 0xf0, 0xe0 },
},
}
+318
View File
@@ -0,0 +1,318 @@
/*
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
An implementation of [shoco](https://github.com/Ed-von-Schleck/shoco) by Christian Schramm.
*/
// package shoco is an implementation of the shoco short string compressor
package shoco
import "core:intrinsics"
import "core:compress"
Shoco_Pack :: struct {
word: u32,
bytes_packed: i8,
bytes_unpacked: i8,
offsets: [8]u16,
masks: [8]i16,
header_mask: u8,
header: u8,
}
Shoco_Model :: struct {
min_char: u8,
max_char: u8,
characters_by_id: []u8,
ids_by_character: [256]i16,
successors_by_bigram: []i8,
successors_reversed: []u8,
character_count: u8,
successor_count: u8,
max_successor_n: i8,
packs: []Shoco_Pack,
}
compress_bound :: proc(uncompressed_size: int) -> (worst_case_compressed_size: int) {
// Worst case compression happens when input is non-ASCII (128-255)
// Encoded as 0x00 + the byte in question.
return uncompressed_size * 2
}
decompress_bound :: proc(compressed_size: int, model := DEFAULT_MODEL) -> (maximum_decompressed_size: int) {
// Best case compression is 2:1
most: f64
for pack in model.packs {
val := f64(compressed_size) / f64(pack.bytes_packed) * f64(pack.bytes_unpacked)
most = max(most, val)
}
return int(most)
}
find_best_encoding :: proc(indices: []i16, n_consecutive: i8, model := DEFAULT_MODEL) -> (res: int) {
for p := len(model.packs); p > 0; p -= 1 {
pack := model.packs[p - 1]
if n_consecutive >= pack.bytes_unpacked {
have_index := true
for i := 0; i < int(pack.bytes_unpacked); i += 1 {
if indices[i] > pack.masks[i] {
have_index = false
break
}
}
if have_index {
return p - 1
}
}
}
return -1
}
validate_model :: proc(model: Shoco_Model) -> (int, compress.Error) {
if len(model.characters_by_id) != int(model.character_count) {
return 0, .Unknown_Compression_Method
}
if len(model.successors_by_bigram) != int(model.character_count) * int(model.character_count) {
return 0, .Unknown_Compression_Method
}
if len(model.successors_reversed) != int(model.successor_count) * int(model.max_char - model.min_char) {
return 0, .Unknown_Compression_Method
}
// Model seems legit.
return 0, nil
}
// Decompresses into provided buffer.
decompress_slice_to_output_buffer :: proc(input: []u8, output: []u8, model := DEFAULT_MODEL) -> (size: int, err: compress.Error) {
inp, inp_end := 0, len(input)
out, out_end := 0, len(output)
validate_model(model) or_return
for inp < inp_end {
val := transmute(i8)input[inp]
mark := int(-1)
for val < 0 {
val <<= 1
mark += 1
}
if mark > len(model.packs) {
return out, .Unknown_Compression_Method
}
if mark < 0 {
if out >= out_end {
return out, .Output_Too_Short
}
// Ignore the sentinel value for non-ASCII chars
if input[inp] == 0x00 {
inp += 1
if inp >= inp_end {
return out, .Stream_Too_Short
}
}
output[out] = input[inp]
inp, out = inp + 1, out + 1
} else {
pack := model.packs[mark]
if out + int(pack.bytes_unpacked) > out_end {
return out, .Output_Too_Short
} else if inp + int(pack.bytes_packed) > inp_end {
return out, .Stream_Too_Short
}
code := intrinsics.unaligned_load((^u32)(&input[inp]))
when ODIN_ENDIAN == .Little {
code = intrinsics.byte_swap(code)
}
// Unpack the leading char
offset := pack.offsets[0]
mask := pack.masks[0]
last_chr := model.characters_by_id[(code >> offset) & u32(mask)]
output[out] = last_chr
// Unpack the successor chars
for i := 1; i < int(pack.bytes_unpacked); i += 1 {
offset = pack.offsets[i]
mask = pack.masks[i]
index_major := u32(last_chr - model.min_char) * u32(model.successor_count)
index_minor := (code >> offset) & u32(mask)
last_chr = model.successors_reversed[index_major + index_minor]
output[out + i] = last_chr
}
out += int(pack.bytes_unpacked)
inp += int(pack.bytes_packed)
}
}
return out, nil
}
decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (res: string, err: compress.Error) {
context.allocator = allocator
if len(input) == 0 {
return "", .Stream_Too_Short
}
max_output_size := decompress_bound(len(input), model)
buf: [dynamic]u8
if !resize(&buf, max_output_size) {
return "", .Out_Of_Memory
}
length, result := decompress_slice_to_output_buffer(input, buf[:])
resize(&buf, length)
return string(buf[:]), result
}
decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_MODEL, allocator := context.allocator) -> (size: int, err: compress.Error) {
inp, inp_end := 0, len(input)
out, out_end := 0, len(output)
output := output
validate_model(model) or_return
indices := make([]i16, model.max_successor_n + 1)
defer delete(indices)
last_resort := false
encode: for inp < inp_end {
if last_resort {
last_resort = false
if input[inp] & 0x80 == 0x80 {
// Non-ASCII case
if out + 2 > out_end {
return out, .Output_Too_Short
}
// Put in a sentinel byte
output[out] = 0x00
out += 1
} else {
// An ASCII byte
if out + 1 > out_end {
return out, .Output_Too_Short
}
}
output[out] = input[inp]
out, inp = out + 1, inp + 1
} else {
// Find the longest string of known successors
indices[0] = model.ids_by_character[input[inp]]
last_chr_index := indices[0]
if last_chr_index < 0 {
last_resort = true
continue encode
}
rest := inp_end - inp
n_consecutive: i8 = 1
for ; n_consecutive <= model.max_successor_n; n_consecutive += 1 {
if inp_end > 0 && int(n_consecutive) == rest {
break
}
current_index := model.ids_by_character[input[inp + int(n_consecutive)]]
if current_index < 0 { // '\0' is always -1
break
}
successor_index := model.successors_by_bigram[last_chr_index * i16(model.character_count) + current_index]
if successor_index < 0 {
break
}
indices[n_consecutive] = i16(successor_index)
last_chr_index = current_index
}
if n_consecutive < 2 {
last_resort = true
continue encode
}
pack_n := find_best_encoding(indices, n_consecutive)
if pack_n >= 0 {
if out + int(model.packs[pack_n].bytes_packed) > out_end {
return out, .Output_Too_Short
}
pack := model.packs[pack_n]
code := pack.word
for i := 0; i < int(pack.bytes_unpacked); i += 1 {
code |= u32(indices[i]) << pack.offsets[i]
}
// In the little-endian world, we need to swap what's in the register to match the memory representation.
when ODIN_ENDIAN == .Little {
code = intrinsics.byte_swap(code)
}
out_ptr := raw_data(output[out:])
switch pack.bytes_packed {
case 4:
intrinsics.unaligned_store(transmute(^u32)out_ptr, code)
case 2:
intrinsics.unaligned_store(transmute(^u16)out_ptr, u16(code))
case 1:
intrinsics.unaligned_store(transmute(^u8)out_ptr, u8(code))
case:
return out, .Unknown_Compression_Method
}
out += int(pack.bytes_packed)
inp += int(pack.bytes_unpacked)
} else {
last_resort = true
continue encode
}
}
}
return out, nil
}
compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := context.allocator) -> (output: []u8, err: compress.Error) {
context.allocator = allocator
if len(input) == 0 {
return {}, .Stream_Too_Short
}
max_output_size := compress_bound(len(input))
buf: [dynamic]u8
if !resize(&buf, max_output_size) {
return {}, .Out_Of_Memory
}
length, result := compress_string_to_buffer(input, buf[:])
resize(&buf, length)
return buf[:length], result
}
compress :: proc{compress_string_to_buffer, compress_string}
+32 -27
View File
@@ -1,42 +1,47 @@
//+ignore
package zlib
import "core:compress/zlib"
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
An example of how to use `zlib.inflate`.
*/
import "core:bytes"
import "core:fmt"
main :: proc() {
ODIN_DEMO := []u8{
120, 156, 101, 144, 77, 110, 131, 48, 16, 133, 215, 204, 41, 158, 44,
69, 73, 32, 148, 182, 75, 35, 14, 208, 125, 47, 96, 185, 195, 143,
130, 13, 50, 38, 81, 84, 101, 213, 75, 116, 215, 43, 246, 8, 53,
82, 126, 8, 181, 188, 152, 153, 111, 222, 147, 159, 123, 165, 247, 170,
98, 24, 213, 88, 162, 198, 244, 157, 243, 16, 186, 115, 44, 75, 227,
5, 77, 115, 72, 137, 222, 117, 122, 179, 197, 39, 69, 161, 170, 156,
50, 144, 5, 68, 130, 4, 49, 126, 127, 190, 191, 144, 34, 19, 57,
69, 74, 235, 209, 140, 173, 242, 157, 155, 54, 158, 115, 162, 168, 12,
181, 239, 246, 108, 17, 188, 174, 242, 224, 20, 13, 199, 198, 235, 250,
194, 166, 129, 86, 3, 99, 157, 172, 37, 230, 62, 73, 129, 151, 252,
70, 211, 5, 77, 31, 104, 188, 160, 113, 129, 215, 59, 205, 22, 52,
123, 160, 83, 142, 255, 242, 89, 123, 93, 149, 200, 50, 188, 85, 54,
252, 18, 248, 192, 238, 228, 235, 198, 86, 224, 118, 224, 176, 113, 166,
112, 67, 106, 227, 159, 122, 215, 88, 95, 110, 196, 123, 205, 183, 224,
98, 53, 8, 104, 213, 234, 201, 147, 7, 248, 192, 14, 170, 29, 25,
171, 15, 18, 59, 138, 112, 63, 23, 205, 110, 254, 136, 109, 78, 231,
63, 234, 138, 133, 204,
};
120, 218, 101, 144, 65, 110, 131, 48, 16, 69, 215, 246, 41, 190, 44, 69, 73, 32, 148, 182,
75, 75, 28, 32, 251, 46, 217, 88, 238, 0, 86, 192, 32, 219, 36, 170, 170, 172, 122, 137,
238, 122, 197, 30, 161, 70, 162, 20, 81, 203, 139, 25, 191, 255, 191, 60, 51, 40, 125, 81,
53, 33, 144, 15, 156, 155, 110, 232, 93, 128, 208, 189, 35, 89, 117, 65, 112, 222, 41, 99,
33, 37, 6, 215, 235, 195, 17, 239, 156, 197, 170, 118, 170, 131, 44, 32, 82, 164, 72, 240,
253, 245, 249, 129, 12, 185, 224, 76, 105, 61, 118, 99, 171, 66, 239, 38, 193, 35, 103, 85,
172, 66, 127, 33, 139, 24, 244, 235, 141, 49, 204, 223, 76, 208, 205, 204, 166, 7, 173, 60,
97, 159, 238, 37, 214, 41, 105, 129, 167, 5, 102, 27, 152, 173, 97, 178, 129, 73, 129, 231,
5, 230, 27, 152, 175, 225, 52, 192, 127, 243, 170, 157, 149, 18, 121, 142, 115, 109, 227, 122,
64, 87, 114, 111, 161, 49, 182, 6, 181, 158, 162, 226, 206, 167, 27, 215, 246, 48, 56, 99,
67, 117, 16, 47, 13, 45, 35, 151, 98, 231, 75, 1, 173, 90, 61, 101, 146, 71, 136, 244,
170, 218, 145, 176, 123, 45, 173, 56, 113, 134, 191, 51, 219, 78, 235, 95, 28, 249, 253, 7,
159, 150, 133, 125,
}
OUTPUT_SIZE :: 432
buf: bytes.Buffer;
buf: bytes.Buffer
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
err := zlib.inflate(ODIN_DEMO, &buf);
defer bytes.buffer_destroy(&buf);
err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
defer bytes.buffer_destroy(&buf)
if err != nil {
fmt.printf("\nError: %v\n", err);
fmt.printf("\nError: %v\n", err)
}
s := bytes.buffer_to_string(&buf);
fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s);
assert(len(s) == 438);
s := bytes.buffer_to_string(&buf)
fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s)
assert(len(s) == OUTPUT_SIZE)
}
+371 -297
View File
@@ -1,17 +1,34 @@
package zlib
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
Ginger Bill: Cosmetic changes.
*/
import "core:compress"
import "core:mem"
import "core:io"
import "core:bytes"
import "core:hash"
import "core:bytes"
/*
zlib.inflate decompresses a ZLIB stream passed in as a []u8 or io.Stream.
Returns: Error.
*/
Context :: compress.Context;
/*
Do we do Adler32 as we write bytes to output?
It used to be faster to do it inline, now it's faster to do it at the end of `inflate`.
We'll see what's faster after more optimization, and might end up removing
`Context.rolling_hash` if not inlining it is still faster.
*/
Compression_Method :: enum u8 {
DEFLATE = 8,
@@ -30,41 +47,41 @@ Options :: struct {
level: u8,
}
Error :: compress.Error;
E_General :: compress.General_Error;
E_ZLIB :: compress.ZLIB_Error;
E_Deflate :: compress.Deflate_Error;
Error :: compress.Error
General_Error :: compress.General_Error
ZLIB_Error :: compress.ZLIB_Error
Deflate_Error :: compress.Deflate_Error
DEFLATE_MAX_CHUNK_SIZE :: 65535;
DEFLATE_MAX_LITERAL_SIZE :: 65535;
DEFLATE_MAX_DISTANCE :: 32768;
DEFLATE_MAX_LENGTH :: 258;
DEFLATE_MAX_CHUNK_SIZE :: 65535
DEFLATE_MAX_LITERAL_SIZE :: 65535
DEFLATE_MAX_DISTANCE :: 32768
DEFLATE_MAX_LENGTH :: 258
HUFFMAN_MAX_BITS :: 16;
HUFFMAN_FAST_BITS :: 9;
HUFFMAN_FAST_MASK :: ((1 << HUFFMAN_FAST_BITS) - 1);
HUFFMAN_MAX_BITS :: 16
HUFFMAN_FAST_BITS :: 9
HUFFMAN_FAST_MASK :: ((1 << HUFFMAN_FAST_BITS) - 1)
Z_LENGTH_BASE := [31]u16{
3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,
67,83,99,115,131,163,195,227,258,0,0,
};
}
Z_LENGTH_EXTRA := [31]u8{
0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,
};
}
Z_DIST_BASE := [32]u16{
1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0,
};
}
Z_DIST_EXTRA := [32]u8{
0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0,
};
}
Z_LENGTH_DEZIGZAG := []u8{
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
};
}
Z_FIXED_LENGTH := [288]u8{
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
@@ -76,17 +93,17 @@ Z_FIXED_LENGTH := [288]u8{
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,
};
}
Z_FIXED_DIST := [32]u8{
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
};
}
/*
Accelerate all cases in default tables.
*/
ZFAST_BITS :: 9;
ZFAST_MASK :: ((1 << ZFAST_BITS) - 1);
ZFAST_BITS :: 9
ZFAST_MASK :: ((1 << ZFAST_BITS) - 1)
/*
ZLIB-style Huffman encoding.
@@ -94,203 +111,285 @@ ZFAST_MASK :: ((1 << ZFAST_BITS) - 1);
*/
Huffman_Table :: struct {
fast: [1 << ZFAST_BITS]u16,
firstcode: [16]u16,
firstcode: [17]u16,
maxcode: [17]int,
firstsymbol: [16]u16,
firstsymbol: [17]u16,
size: [288]u8,
value: [288]u16,
};
}
// Implementation starts here
@(optimization_mode="speed")
z_bit_reverse :: #force_inline proc(n: u16, bits: u8) -> (r: u16) {
assert(bits <= 16);
assert(bits <= 16)
// NOTE: Can optimize with llvm.bitreverse.i64 or some bit twiddling
// by reversing all of the bits and masking out the unneeded ones.
r = n;
r = ((r & 0xAAAA) >> 1) | ((r & 0x5555) << 1);
r = ((r & 0xCCCC) >> 2) | ((r & 0x3333) << 2);
r = ((r & 0xF0F0) >> 4) | ((r & 0x0F0F) << 4);
r = ((r & 0xFF00) >> 8) | ((r & 0x00FF) << 8);
r = n
r = ((r & 0xAAAA) >> 1) | ((r & 0x5555) << 1)
r = ((r & 0xCCCC) >> 2) | ((r & 0x3333) << 2)
r = ((r & 0xF0F0) >> 4) | ((r & 0x0F0F) << 4)
r = ((r & 0xFF00) >> 8) | ((r & 0x00FF) << 8)
r >>= (16 - bits);
return;
r >>= (16 - bits)
return
}
write_byte :: #force_inline proc(z: ^Context, c: u8) -> (err: io.Error) #no_bounds_check {
c := c;
buf := transmute([]u8)mem.Raw_Slice{data=&c, len=1};
z.rolling_hash = hash.adler32(buf, z.rolling_hash);
_, e := z.output->impl_write(buf);
if e != .None {
return e;
@(optimization_mode="speed")
grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
/*
That we get here at all means that we didn't pass an expected output size,
or that it was too little.
*/
/*
Double until we reach the maximum allowed.
*/
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX)
resize(buf, new_size)
if len(buf) != new_size {
/*
Resize failed.
*/
return .Resize_Failed
}
z.last[z.bytes_written % z.window_size] = c;
z.bytes_written += 1;
return .None;
return nil
}
/*
TODO: Make these return compress.Error.
*/
@(optimization_mode="speed")
write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_check {
/*
Resize if needed.
*/
if int(z.bytes_written) + 1 >= len(z.output.buf) {
e := grow_buffer(&z.output.buf)
if e != nil {
return .Short_Write
}
}
#no_bounds_check {
z.output.buf[z.bytes_written] = c
}
z.bytes_written += 1
return .None
}
@(optimization_mode="speed")
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
/*
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
without having to worry about wrapping, so no need for a temp allocation to give to
the output stream, just give it _that_ slice.
*/
/*
Resize if needed.
*/
if int(z.bytes_written) + int(count) >= len(z.output.buf) {
e := grow_buffer(&z.output.buf)
if e != nil {
return .Short_Write
}
}
#no_bounds_check {
for _ in 0..<count {
z.output.buf[z.bytes_written] = c
z.bytes_written += 1
}
}
return .None
}
@(optimization_mode="speed")
repl_bytes :: proc(z: ^$C, count: u16, distance: u16) -> (err: io.Error) {
/*
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
without having to worry about wrapping, so no need for a temp allocation to give to
the output stream, just give it _that_ slice.
*/
offset := i64(distance)
if int(z.bytes_written) + int(count) >= len(z.output.buf) {
e := grow_buffer(&z.output.buf)
if e != nil {
return .Short_Write
}
}
#no_bounds_check {
for _ in 0..<count {
c := z.output.buf[z.bytes_written - offset]
z.output.buf[z.bytes_written] = c
z.bytes_written += 1
}
}
return .None
}
allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_Table, err: Error) {
z = new(Huffman_Table, allocator);
return z, nil;
return new(Huffman_Table, allocator), nil
}
@(optimization_mode="speed")
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
sizes: [HUFFMAN_MAX_BITS+1]int;
next_code: [HUFFMAN_MAX_BITS]int;
sizes: [HUFFMAN_MAX_BITS+1]int
next_code: [HUFFMAN_MAX_BITS+1]int
k := int(0);
k := int(0)
mem.zero_slice(sizes[:]);
mem.zero_slice(z.fast[:]);
mem.zero_slice(sizes[:])
mem.zero_slice(z.fast[:])
for v, _ in code_lengths {
sizes[v] += 1;
for v in code_lengths {
sizes[v] += 1
}
sizes[0] = 0;
sizes[0] = 0
for i in 1..16 {
for i in 1 ..< HUFFMAN_MAX_BITS {
if sizes[i] > (1 << uint(i)) {
return E_Deflate.Huffman_Bad_Sizes;
return .Huffman_Bad_Sizes
}
}
code := int(0);
code := int(0)
for i in 1..<16 {
next_code[i] = code;
z.firstcode[i] = u16(code);
z.firstsymbol[i] = u16(k);
code = code + sizes[i];
for i in 1 ..= HUFFMAN_MAX_BITS {
next_code[i] = code
z.firstcode[i] = u16(code)
z.firstsymbol[i] = u16(k)
code = code + sizes[i]
if sizes[i] != 0 {
if (code - 1 >= (1 << u16(i))) {
return E_Deflate.Huffman_Bad_Code_Lengths;
if code - 1 >= (1 << u16(i)) {
return .Huffman_Bad_Code_Lengths
}
}
z.maxcode[i] = code << (16 - uint(i));
code <<= 1;
k += int(sizes[i]);
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
code <<= 1
k += int(sizes[i])
}
z.maxcode[16] = 0x10000; // Sentinel
c: int;
z.maxcode[HUFFMAN_MAX_BITS] = 0x10000 // Sentinel
c: int
for v, ci in code_lengths {
if v != 0 {
c = next_code[v] - int(z.firstcode[v]) + int(z.firstsymbol[v]);
fastv := u16((u16(v) << 9) | u16(ci));
z.size[c] = u8(v);
z.value[c] = u16(ci);
if (v <= ZFAST_BITS) {
j := z_bit_reverse(u16(next_code[v]), v);
c = next_code[v] - int(z.firstcode[v]) + int(z.firstsymbol[v])
fastv := u16((u16(v) << 9) | u16(ci))
z.size[c] = u8(v)
z.value[c] = u16(ci)
if v <= ZFAST_BITS {
j := z_bit_reverse(u16(next_code[v]), v)
for j < (1 << ZFAST_BITS) {
z.fast[j] = fastv;
j += (1 << v);
z.fast[j] = fastv
j += (1 << v)
}
}
next_code[v] += 1;
next_code[v] += 1
}
}
return nil;
return nil
}
decode_huffman_slowpath :: proc(z: ^Context, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
@(optimization_mode="speed")
decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
code := u16(compress.peek_bits_lsb(z,16))
r = 0;
err = nil;
k: int;
s: u8;
code := u16(compress.peek_bits_lsb(z, 16));
k = int(z_bit_reverse(code, 16));
k := int(z_bit_reverse(code, 16))
s: u8
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
if k < t.maxcode[s] {
break;
break
}
s += 1;
s += 1
}
if (s >= 16) {
return 0, E_Deflate.Bad_Huffman_Code;
if s >= 16 {
return 0, .Bad_Huffman_Code
}
// code size is s, so:
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s]);
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
if b >= size_of(t.size) {
return 0, E_Deflate.Bad_Huffman_Code;
return 0, .Bad_Huffman_Code
}
if t.size[b] != s {
return 0, E_Deflate.Bad_Huffman_Code;
return 0, .Bad_Huffman_Code
}
compress.consume_bits_lsb(z, s);
compress.consume_bits_lsb(z, s)
r = t.value[b];
return r, nil;
r = t.value[b]
return r, nil
}
decode_huffman :: proc(z: ^Context, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
@(optimization_mode="speed")
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
if z.num_bits < 16 {
if z.num_bits == -100 {
return 0, E_ZLIB.Code_Buffer_Malformed;
if z.num_bits > 63 {
return 0, .Code_Buffer_Malformed
}
compress.refill_lsb(z);
if z.eof {
return 0, E_General.Stream_Too_Short;
compress.refill_lsb(z)
if z.num_bits > 63 {
return 0, .Stream_Too_Short
}
}
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK];
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
if b != 0 {
s := u8(b >> ZFAST_BITS);
compress.consume_bits_lsb(z, s);
return b & 511, nil;
s := u8(b >> ZFAST_BITS)
compress.consume_bits_lsb(z, s)
return b & 511, nil
}
return decode_huffman_slowpath(z, t);
return decode_huffman_slowpath(z, t)
}
parse_huffman_block :: proc(z: ^Context, z_repeat, z_offset: ^Huffman_Table) -> (err: Error) #no_bounds_check {
@(optimization_mode="speed")
parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: Error) #no_bounds_check {
#no_bounds_check for {
value, e := decode_huffman(z, z_repeat);
value, e := decode_huffman(z, z_repeat)
if e != nil {
return err;
return err
}
if value < 256 {
e := write_byte(z, u8(value));
e := write_byte(z, u8(value))
if e != .None {
return E_General.Output_Too_Short;
return .Output_Too_Short
}
} else {
if value == 256 {
// End of block
return nil;
// End of block
return nil
}
value -= 257;
length := Z_LENGTH_BASE[value];
value -= 257
length := Z_LENGTH_BASE[value]
if Z_LENGTH_EXTRA[value] > 0 {
length += u16(compress.read_bits_lsb(z, Z_LENGTH_EXTRA[value]));
length += u16(compress.read_bits_lsb(z, Z_LENGTH_EXTRA[value]))
}
value, e = decode_huffman(z, z_offset);
value, e = decode_huffman(z, z_offset)
if e != nil {
return E_Deflate.Bad_Huffman_Code;
return .Bad_Huffman_Code
}
distance := Z_DIST_BASE[value];
distance := Z_DIST_BASE[value]
if Z_DIST_EXTRA[value] > 0 {
distance += u16(compress.read_bits_lsb(z, Z_DIST_EXTRA[value]));
distance += u16(compress.read_bits_lsb(z, Z_DIST_EXTRA[value]))
}
if z.bytes_written < i64(distance) {
// Distance is longer than we've decoded so far.
return E_Deflate.Bad_Distance;
return .Bad_Distance
}
offset := i64(z.bytes_written - i64(distance));
/*
These might be sped up with a repl_byte call that copies
from the already written output more directly, and that
@@ -303,23 +402,17 @@ parse_huffman_block :: proc(z: ^Context, z_repeat, z_offset: ^Huffman_Table) ->
Replicate the last outputted byte, length times.
*/
if length > 0 {
b, e := compress.peek_back_byte(z, offset);
c := z.output.buf[z.bytes_written - i64(distance)]
e := repl_byte(z, length, c)
if e != .None {
return E_General.Output_Too_Short;
}
#no_bounds_check for _ in 0..<length {
write_byte(z, b);
return .Output_Too_Short
}
}
} else {
if length > 0 {
#no_bounds_check for _ in 0..<length {
b, e := compress.peek_back_byte(z, offset);
if e != .None {
return E_General.Output_Too_Short;
}
write_byte(z, b);
offset += 1;
e := repl_bytes(z, length, distance)
if e != .None {
return .Output_Too_Short
}
}
}
@@ -327,53 +420,45 @@ parse_huffman_block :: proc(z: ^Context, z_repeat, z_offset: ^Huffman_Table) ->
}
}
inflate_from_stream :: proc(using ctx: ^Context, raw := false, allocator := context.allocator) -> (err: Error) #no_bounds_check {
@(optimization_mode="speed")
inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := false, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check {
/*
ctx.input must be an io.Stream backed by an implementation that supports:
- read
- size
ctx.output must be an io.Stream backed by an implementation that supports:
- write
ctx.output must be a bytes.Buffer for now. We'll add a separate implementation that writes to a stream.
raw determines whether the ZLIB header is processed, or we're inflating a raw
DEFLATE stream.
*/
if !raw {
data_size := io.size(ctx.input);
if data_size < 6 {
return E_General.Stream_Too_Short;
size, size_err := compress.input_size(ctx)
if size < 6 || size_err != nil {
return .Stream_Too_Short
}
cmf, _ := compress.read_u8(ctx);
cmf, _ := compress.read_u8(ctx)
method := Compression_Method(cmf & 0xf);
method := Compression_Method(cmf & 0xf)
if method != .DEFLATE {
return E_General.Unknown_Compression_Method;
return .Unknown_Compression_Method
}
cinfo := (cmf >> 4) & 0xf;
if cinfo > 7 {
return E_ZLIB.Unsupported_Window_Size;
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
return .Unsupported_Window_Size
}
ctx.window_size = 1 << (cinfo + 8);
flg, _ := compress.read_u8(ctx)
flg, _ := compress.read_u8(ctx);
fcheck := flg & 0x1f;
fcheck_computed := (cmf << 8 | flg) & 0x1f;
fcheck := flg & 0x1f
fcheck_computed := (cmf << 8 | flg) & 0x1f
if fcheck != fcheck_computed {
return E_General.Checksum_Failed;
return .Checksum_Failed
}
fdict := (flg >> 5) & 1;
/*
We don't handle built-in dictionaries for now.
They're application specific and PNG doesn't use them.
*/
if fdict != 0 {
return E_ZLIB.FDICT_Unsupported;
if fdict := (flg >> 5) & 1; fdict != 0 {
return .FDICT_Unsupported
}
// flevel := Compression_Level((flg >> 6) & 3);
@@ -383,85 +468,94 @@ inflate_from_stream :: proc(using ctx: ^Context, raw := false, allocator := cont
at the end to compare checksums.
*/
// Seed the Adler32 rolling checksum.
ctx.rolling_hash = 1;
}
// Parse ZLIB stream without header.
err = inflate_raw(ctx);
if err != nil {
return err;
}
// Parse ZLIB stream without header.
inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return
if !raw {
compress.discard_to_next_byte_lsb(ctx);
compress.discard_to_next_byte_lsb(ctx)
adler32 := compress.read_bits_lsb(ctx, 8) << 24 | compress.read_bits_lsb(ctx, 8) << 16 | compress.read_bits_lsb(ctx, 8) << 8 | compress.read_bits_lsb(ctx, 8);
if ctx.rolling_hash != u32(adler32) {
return E_General.Checksum_Failed;
adler_b: [4]u8
for _, i in adler_b {
adler_b[i], _ = compress.read_u8_prefer_code_buffer_lsb(ctx)
}
adler := transmute(u32be)adler_b
output_hash := hash.adler32(ctx.output.buf[:])
if output_hash != u32(adler) {
return .Checksum_Failed
}
}
return nil;
return nil
}
// @(optimization_mode="speed")
inflate_from_stream_raw :: proc(z: ^Context, allocator := context.allocator) -> (err: Error) #no_bounds_check {
final := u32(0);
type := u32(0);
// TODO: Check alignment of reserve/resize.
z.num_bits = 0;
z.code_buffer = 0;
@(optimization_mode="speed")
inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check {
context.allocator = allocator
expected_output_size := expected_output_size
z_repeat: ^Huffman_Table;
z_offset: ^Huffman_Table;
codelength_ht: ^Huffman_Table;
/*
Always set up a minimum allocation size.
*/
expected_output_size = max(max(expected_output_size, compress.COMPRESS_OUTPUT_ALLOCATE_MIN), 512)
z_repeat, err = allocate_huffman_table(allocator=context.allocator);
if err != nil {
return err;
}
z_offset, err = allocate_huffman_table(allocator=context.allocator);
if err != nil {
return err;
}
codelength_ht, err = allocate_huffman_table(allocator=context.allocator);
if err != nil {
return err;
}
defer free(z_repeat);
defer free(z_offset);
defer free(codelength_ht);
// fmt.printf("\nZLIB: Expected Payload Size: %v\n\n", expected_output_size);
if z.window_size == 0 {
z.window_size = DEFLATE_MAX_DISTANCE;
if expected_output_size > 0 && expected_output_size <= compress.COMPRESS_OUTPUT_ALLOCATE_MAX {
/*
Try to pre-allocate the output buffer.
*/
reserve(&z.output.buf, expected_output_size)
resize (&z.output.buf, expected_output_size)
}
// Allocate rolling window buffer.
last_b := mem.make_dynamic_array_len_cap([dynamic]u8, z.window_size, z.window_size, allocator);
z.last = &last_b;
defer delete(last_b);
if len(z.output.buf) != expected_output_size {
return .Resize_Failed
}
z.num_bits = 0
z.code_buffer = 0
z_repeat: ^Huffman_Table
z_offset: ^Huffman_Table
codelength_ht: ^Huffman_Table
defer free(z_repeat)
defer free(z_offset)
defer free(codelength_ht)
z_repeat = allocate_huffman_table() or_return
z_offset = allocate_huffman_table() or_return
codelength_ht = allocate_huffman_table() or_return
final := u32(0)
type := u32(0)
for {
final = compress.read_bits_lsb(z, 1);
type = compress.read_bits_lsb(z, 2);
final = compress.read_bits_lsb(z, 1)
type = compress.read_bits_lsb(z, 2)
// fmt.printf("Final: %v | Type: %v\n", final, type);
// fmt.printf("Final: %v | Type: %v\n", final, type)
switch type {
case 0:
// fmt.printf("Method 0: STORED\n")
// Uncompressed block
// Discard bits until next byte boundary
compress.discard_to_next_byte_lsb(z);
compress.discard_to_next_byte_lsb(z)
uncompressed_len := i16(compress.read_bits_lsb(z, 16));
length_check := i16(compress.read_bits_lsb(z, 16));
uncompressed_len := u16(compress.read_bits_lsb(z, 16))
length_check := u16(compress.read_bits_lsb(z, 16))
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check)
if ~uncompressed_len != length_check {
return E_Deflate.Len_Nlen_Mismatch;
return .Len_Nlen_Mismatch
}
/*
@@ -469,138 +563,118 @@ inflate_from_stream_raw :: proc(z: ^Context, allocator := context.allocator) ->
and a single Adler32 update after.
*/
#no_bounds_check for uncompressed_len > 0 {
compress.refill_lsb(z);
lit := compress.read_bits_lsb(z, 8);
write_byte(z, u8(lit));
uncompressed_len -= 1;
compress.refill_lsb(z)
lit := compress.read_bits_lsb(z, 8)
write_byte(z, u8(lit))
uncompressed_len -= 1
}
assert(uncompressed_len == 0)
case 3:
return E_Deflate.BType_3;
return .BType_3
case:
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
// fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type)
if type == 1 {
// Use fixed code lengths.
err = build_huffman(z_repeat, Z_FIXED_LENGTH[:]);
if err != nil {
return err;
}
err = build_huffman(z_offset, Z_FIXED_DIST[:]);
if err != nil {
return err;
}
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return
build_huffman(z_offset, Z_FIXED_DIST[:]) or_return
} else {
lencodes: [286+32+137]u8;
codelength_sizes: [19]u8;
lencodes: [286+32+137]u8
codelength_sizes: [19]u8
//i: u32;
n: u32;
n: u32
compress.refill_lsb(z, 14);
hlit := compress.read_bits_no_refill_lsb(z, 5) + 257;
hdist := compress.read_bits_no_refill_lsb(z, 5) + 1;
hclen := compress.read_bits_no_refill_lsb(z, 4) + 4;
ntot := hlit + hdist;
compress.refill_lsb(z, 14)
hlit := compress.read_bits_no_refill_lsb(z, 5) + 257
hdist := compress.read_bits_no_refill_lsb(z, 5) + 1
hclen := compress.read_bits_no_refill_lsb(z, 4) + 4
ntot := hlit + hdist
#no_bounds_check for i in 0..<hclen {
s := compress.read_bits_lsb(z, 3);
codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s);
}
err = build_huffman(codelength_ht, codelength_sizes[:]);
if err != nil {
return err;
s := compress.read_bits_lsb(z, 3)
codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s)
}
build_huffman(codelength_ht, codelength_sizes[:]) or_return
n = 0;
c: u16;
n = 0
c: u16
for n < ntot {
c, err = decode_huffman(z, codelength_ht);
if err != nil {
return err;
}
c = decode_huffman(z, codelength_ht) or_return
if c < 0 || c >= 19 {
return E_Deflate.Huffman_Bad_Code_Lengths;
return .Huffman_Bad_Code_Lengths
}
if c < 16 {
lencodes[n] = u8(c);
n += 1;
lencodes[n] = u8(c)
n += 1
} else {
fill := u8(0);
compress.refill_lsb(z, 7);
fill := u8(0)
compress.refill_lsb(z, 7)
switch c {
case 16:
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3);
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
if n == 0 {
return E_Deflate.Huffman_Bad_Code_Lengths;
return .Huffman_Bad_Code_Lengths
}
fill = lencodes[n - 1];
fill = lencodes[n - 1]
case 17:
c = u16(compress.read_bits_no_refill_lsb(z, 3) + 3);
c = u16(compress.read_bits_no_refill_lsb(z, 3) + 3)
case 18:
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11);
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
case:
return E_Deflate.Huffman_Bad_Code_Lengths;
return .Huffman_Bad_Code_Lengths
}
if ntot - n < u32(c) {
return E_Deflate.Huffman_Bad_Code_Lengths;
return .Huffman_Bad_Code_Lengths
}
nc := n + u32(c);
nc := n + u32(c)
#no_bounds_check for ; n < nc; n += 1 {
lencodes[n] = fill;
lencodes[n] = fill
}
}
}
if n != ntot {
return E_Deflate.Huffman_Bad_Code_Lengths;
return .Huffman_Bad_Code_Lengths
}
err = build_huffman(z_repeat, lencodes[:hlit]);
if err != nil {
return err;
}
err = build_huffman(z_offset, lencodes[hlit:ntot]);
if err != nil {
return err;
}
}
err = parse_huffman_block(z, z_repeat, z_offset);
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
if err != nil {
return err;
build_huffman(z_repeat, lencodes[:hlit]) or_return
build_huffman(z_offset, lencodes[hlit:ntot]) or_return
}
parse_huffman_block(z, z_repeat, z_offset) or_return
}
if final == 1 {
break;
break
}
}
return nil;
if int(z.bytes_written) != len(z.output.buf) {
resize(&z.output.buf, int(z.bytes_written))
}
return nil
}
inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false) -> (err: Error) {
ctx := Context{};
inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
ctx := compress.Context_Memory_Input{}
r := bytes.Reader{};
bytes.reader_init(&r, input);
rs := bytes.reader_to_stream(&r);
ctx.input = rs;
ctx.input_data = input
ctx.output = buf
buf := buf;
ws := bytes.buffer_to_stream(buf);
ctx.output = ws;
err = inflate_from_stream(&ctx, raw);
return err;
return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size)
}
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false) -> (err: Error) {
return inflate_from_byte_array(input, buf, true);
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
ctx := compress.Context_Memory_Input{}
ctx.input_data = input
ctx.output = buf
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
}
inflate :: proc{inflate_from_stream, inflate_from_byte_array};
inflate_raw :: proc{inflate_from_stream_raw, inflate_from_byte_array_raw};
inflate :: proc{inflate_from_context, inflate_from_byte_array}
-216
View File
@@ -1,216 +0,0 @@
package container
import "core:mem"
import "core:runtime"
Array :: struct(T: typeid) {
data: ^T,
len: int,
cap: int,
allocator: mem.Allocator,
}
ARRAY_DEFAULT_CAPACITY :: 16;
/*
array_init :: proc {
array_init_none,
array_init_len,
array_init_len_cap,
}
array_init
array_delete
array_len
array_cap
array_space
array_slice
array_get
array_get_ptr
array_set
array_reserve
array_resize
array_push = array_append :: proc{
array_push_back,
array_push_back_elems,
}
array_push_front
array_pop_back
array_pop_front
array_consume
array_trim
array_clear
array_clone
array_set_capacity
array_grow
*/
array_init_none :: proc(a: ^$A/Array, allocator := context.allocator) {
array_init_len_cap(a, 0, ARRAY_DEFAULT_CAPACITY, allocator);
}
array_init_len :: proc(a: ^$A/Array, len: int, allocator := context.allocator) {
array_init_len_cap(a, len, len, allocator);
}
array_init_len_cap :: proc(a: ^$A/Array($T), len: int, cap: int, allocator := context.allocator) {
a.allocator = allocator;
a.data = (^T)(mem.alloc(size_of(T)*cap, align_of(T), a.allocator));
a.len = len;
a.cap = cap;
}
array_init :: proc{array_init_none, array_init_len, array_init_len_cap};
array_delete :: proc(a: $A/Array) {
mem.free(a.data, a.allocator);
}
array_len :: proc(a: $A/Array) -> int {
return a.len;
}
array_cap :: proc(a: $A/Array) -> int {
return a.cap;
}
array_space :: proc(a: $A/Array) -> int {
return a.cap - a.len;
}
array_slice :: proc(a: $A/Array($T)) -> []T {
s := mem.Raw_Slice{a.data, a.len};
return transmute([]T)s;
}
array_cap_slice :: proc(a: $A/Array($T)) -> []T {
s := mem.Raw_Slice{a.data, a.cap};
return transmute([]T)s;
}
array_get :: proc(a: $A/Array($T), index: int, loc := #caller_location) -> T {
runtime.bounds_check_error_loc(loc, index, array_len(a));
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index))^;
}
array_get_ptr :: proc(a: $A/Array($T), index: int, loc := #caller_location) -> ^T {
runtime.bounds_check_error_loc(loc, index, array_len(a));
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index));
}
array_set :: proc(a: ^$A/Array($T), index: int, item: T, loc := #caller_location) {
runtime.bounds_check_error_loc(loc, index, array_len(a^));
(^T)(uintptr(a.data) + size_of(T)*uintptr(index))^ = item;
}
array_reserve :: proc(a: ^$A/Array, capacity: int) {
if capacity > a.len {
array_set_capacity(a, capacity);
}
}
array_resize :: proc(a: ^$A/Array, length: int) {
if length > a.len {
array_set_capacity(a, length);
}
a.len = length;
}
array_push_back :: proc(a: ^$A/Array($T), item: T) {
if array_space(a^) == 0 {
array_grow(a);
}
a.len += 1;
array_set(a, a.len-1, item);
}
array_push_front :: proc(a: ^$A/Array($T), item: T) {
if array_space(a^) == 0 {
array_grow(a);
}
a.len += 1;
data := array_slice(a^);
copy(data[1:], data[:]);
data[0] = item;
}
array_pop_back :: proc(a: ^$A/Array($T), loc := #caller_location) -> T {
assert(condition=a.len > 0, loc=loc);
item := array_get(a^, a.len-1);
a.len -= 1;
return item;
}
array_pop_front :: proc(a: ^$A/Array($T), loc := #caller_location) -> T {
assert(condition=a.len > 0, loc=loc);
item := array_get(a^, 0);
s := array_slice(a^);
copy(s[:], s[1:]);
a.len -= 1;
return item;
}
array_consume :: proc(a: ^$A/Array($T), count: int, loc := #caller_location) {
assert(condition=a.len >= count, loc=loc);
a.len -= count;
}
array_trim :: proc(a: ^$A/Array($T)) {
array_set_capacity(a, a.len);
}
array_clear :: proc(a: ^$A/Array($T)) {
array_resize(a, 0);
}
array_clone :: proc(a: $A/Array($T), allocator := context.allocator) -> A {
res: A;
array_init(&res, array_len(a), array_len(a), allocator);
copy(array_slice(res), array_slice(a));
return res;
}
array_push_back_elems :: proc(a: ^$A/Array($T), items: ..T) {
if array_space(a^) < len(items) {
array_grow(a, a.len + len(items));
}
offset := a.len;
data := array_cap_slice(a^);
n := copy(data[a.len:], items);
a.len += n;
}
array_push :: proc{array_push_back, array_push_back_elems};
array_append :: proc{array_push_back, array_push_back_elems};
array_set_capacity :: proc(a: ^$A/Array($T), new_capacity: int) {
if new_capacity == a.cap {
return;
}
if new_capacity < a.len {
array_resize(a, new_capacity);
}
new_data: ^T;
if new_capacity > 0 {
if a.allocator.procedure == nil {
a.allocator = context.allocator;
}
new_data = (^T)(mem.alloc(size_of(T)*new_capacity, align_of(T), a.allocator));
if new_data != nil {
mem.copy(new_data, a.data, size_of(T)*a.len);
}
}
mem.free(a.data, a.allocator);
a.data = new_data;
a.cap = new_capacity;
}
array_grow :: proc(a: ^$A/Array, min_capacity: int = 0) {
new_capacity := max(array_len(a^)*2 + 8, min_capacity);
array_set_capacity(a, new_capacity);
}
+239
View File
@@ -0,0 +1,239 @@
package dynamic_bit_array
import "core:intrinsics"
import "core:mem"
/*
Note that these constants are dependent on the backing being a u64.
*/
@(private="file")
INDEX_SHIFT :: 6
@(private="file")
INDEX_MASK :: 63
@(private="file")
NUM_BITS :: 64
Bit_Array :: struct {
bits: [dynamic]u64,
bias: int,
max_index: int,
free_pointer: bool,
}
Bit_Array_Iterator :: struct {
array: ^Bit_Array,
word_idx: int,
bit_idx: uint,
}
/*
In:
- ba: ^Bit_Array - the array to iterate over
Out:
- it: ^Bit_Array_Iterator - the iterator that holds iteration state
*/
make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
return Bit_Array_Iterator { array = ba }
}
/*
In:
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
Out:
- set: bool - the state of the bit at `index`
- index: int - the next bit of the Bit_Array referenced by `it`.
- ok: bool - `true` if the iterator returned a valid index,
`false` if there were no more bits
*/
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
if index > it.array.max_index { return false, 0, false }
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
set = (word >> it.bit_idx & 1) == 1
it.bit_idx += 1
if it.bit_idx >= NUM_BITS {
it.bit_idx = 0
it.word_idx += 1
}
return set, index, true
}
/*
In:
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
Out:
- index: int - the next set bit of the Bit_Array referenced by `it`.
- ok: bool - `true` if the iterator returned a valid index,
`false` if there were no more bits set
*/
iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
return iterate_internal_(it, true)
}
/*
In:
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
Out:
- index: int - the next unset bit of the Bit_Array referenced by `it`.
- ok: bool - `true` if the iterator returned a valid index,
`false` if there were no more unset bits
*/
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
return iterate_internal_(it, false)
}
@(private="file")
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
when ! ITERATE_SET_BITS { word = ~word }
// if the word is empty or we have already gone over all the bits in it,
// b.bit_idx is greater than the index of any set bit in the word,
// meaning that word >> b.bit_idx == 0.
for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
it.word_idx += 1
it.bit_idx = 0
word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
when ! ITERATE_SET_BITS { word = ~word }
}
// if we are iterating the set bits, reaching the end of the array means we have no more bits to check
when ITERATE_SET_BITS {
if it.word_idx >= len(it.array.bits) {
return 0, false
}
}
// reaching here means that the word has some set bits
it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
it.bit_idx += 1
if it.bit_idx >= NUM_BITS {
it.bit_idx = 0
it.word_idx += 1
}
return index, index <= it.array.max_index
}
/*
In:
- ba: ^Bit_Array - a pointer to the Bit Array
- index: The bit index. Can be an enum member.
Out:
- res: The bit you're interested in.
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
The `ok` return value may be ignored.
*/
get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
idx := int(index) - ba.bias
if ba == nil || int(index) < ba.bias { return false, false }
context.allocator = allocator
leg_index := idx >> INDEX_SHIFT
bit_index := idx & INDEX_MASK
/*
If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`.
This early-out prevents unnecessary resizing.
*/
if leg_index + 1 > len(ba.bits) { return false, true }
val := u64(1 << uint(bit_index))
res = ba.bits[leg_index] & val == val
return res, true
}
/*
In:
- ba: ^Bit_Array - a pointer to the Bit Array
- index: The bit index. Can be an enum member.
Out:
- ok: Whether or not we managed to set requested bit.
`set` automatically resizes the Bit Array to accommodate the requested index if needed.
*/
set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
idx := int(index) - ba.bias
if ba == nil || int(index) < ba.bias { return false }
context.allocator = allocator
leg_index := idx >> INDEX_SHIFT
bit_index := idx & INDEX_MASK
resize_if_needed(ba, leg_index) or_return
ba.max_index = max(idx, ba.max_index)
ba.bits[leg_index] |= 1 << uint(bit_index)
return true
}
/*
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
*/
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
context.allocator = allocator
size_in_bits := max_index - min_index
if size_in_bits < 1 { return {}, false }
legs := size_in_bits >> INDEX_SHIFT
res = new(Bit_Array)
res.bias = min_index
res.max_index = max_index
res.free_pointer = true
return res, resize_if_needed(res, legs)
}
/*
Sets all bits to `false`.
*/
clear :: proc(ba: ^Bit_Array) {
if ba == nil { return }
mem.zero_slice(ba.bits[:])
}
/*
Releases the memory used by the Bit Array.
*/
destroy :: proc(ba: ^Bit_Array) {
if ba == nil { return }
delete(ba.bits)
if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
free(ba)
}
}
/*
Resizes the Bit Array. For internal use.
If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
*/
@(private="file")
resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocator) -> (ok: bool) {
if ba == nil { return false }
context.allocator = allocator
if legs + 1 > len(ba.bits) {
resize(&ba.bits, legs + 1)
}
return len(ba.bits) > legs
}
+53
View File
@@ -0,0 +1,53 @@
package dynamic_bit_array
/*
The Bit Array can be used in several ways:
-- By default you don't need to instantiate a Bit Array:
package test
import "core:fmt"
import "core:container/bit_array"
main :: proc() {
using bit_array
bits: Bit_Array
// returns `true`
fmt.println(set(&bits, 42))
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
was_set, was_retrieved := get(&bits, -1)
fmt.println(was_set, was_retrieved)
destroy(&bits)
}
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
package test
import "core:fmt"
import "core:container/bit_array"
main :: proc() {
Foo :: enum int {
Negative_Test = -42,
Bar = 420,
Leaves = 69105,
}
using bit_array
bits := create(int(max(Foo)), int(min(Foo)))
defer destroy(bits)
fmt.printf("Set(Bar): %v\n", set(bits, Foo.Bar))
fmt.printf("Get(Bar): %v, %v\n", get(bits, Foo.Bar))
fmt.printf("Set(Negative_Test): %v\n", set(bits, Foo.Negative_Test))
fmt.printf("Get(Leaves): %v, %v\n", get(bits, Foo.Leaves))
fmt.printf("Get(Negative_Test): %v, %v\n", get(bits, Foo.Negative_Test))
fmt.printf("Freed.\n")
}
*/
-80
View File
@@ -1,80 +0,0 @@
package container
import "core:mem"
Bloom_Hash_Proc :: #type proc(data: []byte) -> u32;
Bloom_Hash :: struct {
hash_proc: Bloom_Hash_Proc,
next: ^Bloom_Hash,
}
Bloom_Filter :: struct {
allocator: mem.Allocator,
hash: ^Bloom_Hash,
bits: []byte,
}
bloom_filter_init :: proc(b: ^Bloom_Filter, size: int, allocator := context.allocator) {
b.allocator = allocator;
b.bits = make([]byte, size, allocator);
}
bloom_filter_destroy :: proc(b: ^Bloom_Filter) {
context.allocator = b.allocator;
delete(b.bits);
for b.hash != nil {
hash := b.hash;
b.hash = b.hash.next;
free(hash);
}
}
bloom_filter_add_hash_proc :: proc(b: ^Bloom_Filter, hash_proc: Bloom_Hash_Proc) {
context.allocator = b.allocator;
h := new(Bloom_Hash);
h.hash_proc = hash_proc;
head := &b.hash;
for head^ != nil {
head = &(head^.next);
}
head^ = h;
}
bloom_filter_add :: proc(b: ^Bloom_Filter, item: []byte) {
#no_bounds_check for h := b.hash; h != nil; h = h.next {
hash := h.hash_proc(item);
hash %= u32(len(b.bits) * 8);
b.bits[hash >> 3] |= 1 << (hash & 3);
}
}
bloom_filter_add_string :: proc(b: ^Bloom_Filter, item: string) {
bloom_filter_add(b, transmute([]byte)item);
}
bloom_filter_add_raw :: proc(b: ^Bloom_Filter, data: rawptr, size: int) {
item := mem.slice_ptr((^byte)(data), size);
bloom_filter_add(b, item);
}
bloom_filter_test :: proc(b: ^Bloom_Filter, item: []byte) -> bool {
#no_bounds_check for h := b.hash; h != nil; h = h.next {
hash := h.hash_proc(item);
hash %= u32(len(b.bits) * 8);
if (b.bits[hash >> 3] & (1 << (hash & 3)) == 0) {
return false;
}
}
return true;
}
bloom_filter_test_string :: proc(b: ^Bloom_Filter, item: string) -> bool {
return bloom_filter_test(b, transmute([]byte)item);
}
bloom_filter_test_raw :: proc(b: ^Bloom_Filter, data: rawptr, size: int) -> bool {
item := mem.slice_ptr((^byte)(data), size);
return bloom_filter_test(b, item);
}
@@ -0,0 +1,173 @@
package container_intrusive_list
import "core:intrinsics"
// An intrusive doubly-linked list
//
// As this is an intrusive container, a `Node` must be embedded in your own
// structure which is conventionally called a "link". The use of `push_front`
// and `push_back` take the address of this node. Retrieving the data
// associated with the node requires finding the relative offset of the node
// of the parent structure. The parent type and field name are given to
// `iterator_*` procedures, or to the built-in `container_of` procedure.
//
// This data structure is two-pointers in size:
// 8 bytes on 32-bit platforms and 16 bytes on 64-bit platforms
List :: struct {
head: ^Node,
tail: ^Node,
}
Node :: struct {
next, prev: ^Node,
}
push_front :: proc(list: ^List, node: ^Node) {
if list.head != nil {
list.head.prev = node
node.prev, node.next = nil, list.head
list.head = node
} else {
list.head, list.tail = node, node
node.prev, node.next = nil, nil
}
}
push_back :: proc(list: ^List, node: ^Node) {
if list.tail != nil {
list.tail.next = node
node.prev, node.next = list.tail, nil
list.tail = node
} else {
list.head, list.tail = node, node
node.prev, node.next = nil, nil
}
}
remove :: proc(list: ^List, node: ^Node) {
if node != nil {
if node.next != nil {
node.next.prev = node.prev
}
if node.prev != nil {
node.prev.next = node.next
}
if list.head == node {
list.head = node.next
}
if list.tail == node {
list.tail = node.prev
}
}
}
remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
for node := list.head; node != nil; {
next := node.next
if to_erase(node) {
if node.next != nil {
node.next.prev = node.prev
}
if node.prev != nil {
node.prev.next = node.next
}
if list.head == node {
list.head = node.next
}
if list.tail == node {
list.tail = node.prev
}
}
node = next
}
}
is_empty :: proc(list: ^List) -> bool {
return list.head == nil
}
pop_front :: proc(list: ^List) -> ^Node {
link := list.head
if link == nil {
return nil
}
if link.next != nil {
link.next.prev = link.prev
}
if link.prev != nil {
link.prev.next = link.next
}
if link == list.head {
list.head = link.next
}
if link == list.tail {
list.tail = link.prev
}
return link
}
pop_back :: proc(list: ^List) -> ^Node {
link := list.tail
if link == nil {
return nil
}
if link.next != nil {
link.next.prev = link.prev
}
if link.prev != nil {
link.prev.next = link.next
}
if link == list.head {
list.head = link.next
}
if link == list.tail {
list.tail = link.prev
}
return link
}
Iterator :: struct($T: typeid) {
curr: ^Node,
offset: uintptr,
}
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node {
return {list.head, offset_of_by_string(T, field_name)}
}
iterator_tail :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node {
return {list.tail, offset_of_by_string(T, field_name)}
}
iterator_from_node :: proc(node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node {
return {node, offset_of_by_string(T, field_name)}
}
iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
node := it.curr
if node == nil {
return nil, false
}
it.curr = node.next
return (^T)(uintptr(node) - it.offset), true
}
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
node := it.curr
if node == nil {
return nil, false
}
it.curr = node.prev
return (^T)(uintptr(node) - it.offset), true
}
+201
View File
@@ -0,0 +1,201 @@
package container_lru
import "core:runtime"
import "core:intrinsics"
_ :: runtime
_ :: intrinsics
Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
prev, next: ^Node(Key, Value),
key: Key,
value: Value,
}
// Cache is an LRU cache. It automatically removes entries as new entries are
// added if the capacity is reached. Entries are removed based on how recently
// they were used where the oldest entries are removed first.
Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
head: ^Node(Key, Value),
tail: ^Node(Key, Value),
entries: map[Key]^Node(Key, Value),
count: int,
capacity: int,
node_allocator: runtime.Allocator,
on_remove: proc(key: Key, value: Value, user_data: rawptr),
on_remove_user_data: rawptr,
}
// init initializes a Cache
init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := context.allocator, node_allocator := context.allocator) {
c.entries.allocator = entries_allocator
c.node_allocator = node_allocator
c.capacity = capacity
}
// destroy deinitializes a Cachem
destroy :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
clear(c, call_on_remove)
delete(c.entries)
}
// clear the contents of a Cache
clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
for _, node in c.entries {
if call_on_remove {
_call_on_remove(c, node)
}
free(node, c.node_allocator)
}
runtime.clear(&c.entries)
c.head = nil
c.tail = nil
c.count = 0
}
// set the given key value pair. This operation updates the recent usage of the item.
set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error {
if e, ok := c.entries[key]; ok {
e.value = value
_pop_node(c, e)
_push_front_node(c, e)
return nil
}
e : ^Node(Key, Value) = nil
assert(c.count <= c.capacity)
if c.count == c.capacity {
e = c.tail
_remove_node(c, e)
}
else {
c.count += 1
e = new(Node(Key, Value), c.node_allocator) or_return
}
e.key = key
e.value = value
_push_front_node(c, e)
c.entries[key] = e
return nil
}
// get a value from the cache from a given key. This operation updates the usage of the item.
get :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
e: ^Node(Key, Value)
e, ok = c.entries[key]
if !ok {
return
}
_pop_node(c, e)
_push_front_node(c, e)
return e.value, true
}
// get_ptr gets the pointer to a value the cache from a given key. This operation updates the usage of the item.
get_ptr :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: ^Value, ok: bool) #optional_ok {
e: ^Node(Key, Value)
e, ok = c.entries[key]
if !ok {
return
}
_pop_node(c, e)
_push_front_node(c, e)
return &e.value, true
}
// peek gets the value from the cache from a given key without updating the recent usage.
peek :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
e: ^Node(Key, Value)
e, ok = c.entries[key]
if !ok {
return
}
return e.value, true
}
// exists checks for the existence of a value from a given key without updating the recent usage.
exists :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
return key in c.entries
}
// remove removes an item from the cache.
remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
e, ok := c.entries[key]
if !ok {
return false
}
_remove_node(c, e)
free(node, c.node_allocator)
c.count -= 1
return true
}
@(private)
_remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
if c.head == node {
c.head = node.next
}
if c.tail == node {
c.tail = node.prev
}
if node.prev != nil {
node.prev.next = node.next
}
if node.next != nil {
node.next.prev = node.prev
}
node.prev = nil
node.next = nil
delete_key(&c.entries, node.key)
_call_on_remove(c, node)
}
@(private)
_call_on_remove :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
if c.on_remove != nil {
c.on_remove(node.key, node.value, c.on_remove_user_data)
}
}
@(private)
_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
if c.head != nil {
e.next = c.head
e.next.prev = e
}
c.head = e
if c.tail == nil {
c.tail = e
}
e.prev = nil
}
@(private)
_pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
if e == nil {
return
}
if c.head == e {
c.head = e.next
}
if c.tail == e {
c.tail = e.prev
}
if e.prev != nil {
e.prev.next = e.next
}
if e.next != nil {
e.next.prev = e.prev
}
e.prev = nil
e.next = nil
}
-377
View File
@@ -1,377 +0,0 @@
package container
import "intrinsics"
_ :: intrinsics;
Map :: struct(Key, Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
hash: Array(int),
entries: Array(Map_Entry(Key, Value)),
}
Map_Entry :: struct(Key, Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
hash: uintptr,
next: int,
key: Key,
value: Value,
}
/*
map_init :: proc{
map_init_none,
map_init_cap,
}
map_delete
map_has
map_get
map_get_default
map_get_ptr
map_set
map_remove
map_reserve
map_clear
// Multi Map
multi_map_find_first
multi_map_find_next
multi_map_count
multi_map_get :: proc{
multi_map_get_array,
multi_map_get_slice,
};
multi_map_get_as_slice
multi_map_insert
multi_map_remove
multi_map_remove_all
*/
map_init :: proc{map_init_none, map_init_cap};
map_init_none :: proc(m: ^$M/Map($Key, $Value), allocator := context.allocator) {
m.hash.allocator = allocator;
m.entries.allocator = allocator;
}
map_init_cap :: proc(m: ^$M/Map($Key, $Value), cap: int, allocator := context.allocator) {
m.hash.allocator = allocator;
m.entries.allocator = allocator;
map_reserve(m, cap);
}
map_delete :: proc(m: $M/Map($Key, $Value)) {
array_delete(m.hash);
array_delete(m.entries);
}
map_has :: proc(m: $M/Map($Key, $Value), key: Key) -> bool {
return _map_find_or_fail(m, key) >= 0;
}
map_get :: proc(m: $M/Map($Key, $Value), key: Key) -> (res: Value, ok: bool) #optional_ok {
i := _map_find_or_fail(m, key);
if i < 0 {
return {}, false;
}
return array_get(m.entries, i).value, true;
}
map_get_default :: proc(m: $M/Map($Key, $Value), key: Key, default: Value) -> (res: Value, ok: bool) #optional_ok {
i := _map_find_or_fail(m, key);
if i < 0 {
return default, false;
}
return array_get(m.entries, i).value, true;
}
map_get_ptr :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Value {
i := _map_find_or_fail(m, key);
if i < 0 {
return nil;
}
return array_get_ptr(m.entries, i).value;
}
map_set :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
if array_len(m.hash) == 0 {
_map_grow(m);
}
i := _map_find_or_make(m, key);
array_get_ptr(m.entries, i).value = value;
if _map_full(m^) {
_map_grow(m);
}
}
map_remove :: proc(m: ^$M/Map($Key, $Value), key: Key) {
fr := _map_find_key(m^, key);
if fr.entry_index >= 0 {
_map_erase(m, fr);
}
}
map_reserve :: proc(m: ^$M/Map($Key, $Value), new_size: int) {
nm: M;
map_init(&nm, m.hash.allocator);
array_resize(&nm.hash, new_size);
array_reserve(&nm.entries, array_len(m.entries));
for i in 0..<new_size {
array_set(&nm.hash, i, -1);
}
for i in 0..<array_len(m.entries) {
e := array_get(m.entries, i);
multi_map_insert(&nm, e.key, e.value);
}
map_delete(m^);
m^ = nm;
}
map_clear :: proc(m: ^$M/Map($Key, $Value)) {
array_clear(&m.hash);
array_clear(&m.entries);
}
multi_map_find_first :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Map_Entry(Key, Value) {
i := _map_find_or_fail(m, key);
if i < 0 {
return nil;
}
return array_get_ptr(m.entries, i);
}
multi_map_find_next :: proc(m: $M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) -> ^Map_Entry(Key, Value) {
i := e.next;
for i >= 0 {
it := array_get_ptr(m.entries, i);
if it.hash == e.hash && it.key == e.key {
return it;
}
i = it.next;
}
return nil;
}
multi_map_count :: proc(m: $M/Map($Key, $Value), key: Key) -> int {
n := 0;
e := multi_map_find_first(m, key);
for e != nil {
n += 1;
e = multi_map_find_next(m, e);
}
return n;
}
multi_map_get :: proc{multi_map_get_array, multi_map_get_slice};
multi_map_get_array :: proc(m: $M/Map($Key, $Value), key: Key, items: ^Array(Value)) {
if items == nil {
return;
}
e := multi_map_find_first(m, key);
for e != nil {
array_append(items, e.value);
e = multi_map_find_next(m, e);
}
}
multi_map_get_slice :: proc(m: $M/Map($Key, $Value), key: Key, items: []Value) {
e := multi_map_find_first(m, key);
i := 0;
for e != nil && i < len(items) {
items[i] = e.value;
i += 1;
e = multi_map_find_next(m, e);
}
}
multi_map_get_as_slice :: proc(m: $M/Map($Key, $Value), key: Key) -> []Value {
items: Array(Value);
array_init(&items, 0);
e := multi_map_find_first(m, key);
for e != nil {
array_append(&items, e.value);
e = multi_map_find_next(m, e);
}
return array_slice(items);
}
multi_map_insert :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
if array_len(m.hash) == 0 {
_map_grow(m);
}
i := _map_make(m, key);
array_get_ptr(m.entries, i).value = value;
if _map_full(m^) {
_map_grow(m);
}
}
multi_map_remove :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) {
fr := _map_find_entry(m, e);
if fr.entry_index >= 0 {
_map_erase(m, fr);
}
}
multi_map_remove_all :: proc(m: ^$M/Map($Key, $Value), key: Key) {
for map_exist(m^, key) {
map_remove(m, key);
}
}
/// Internal
Map_Find_Result :: struct {
hash_index: int,
entry_prev: int,
entry_index: int,
}
_map_add_entry :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int where intrinsics.type_is_valid_map_key(Key) {
hasher := intrinsics.type_hasher_proc(Key);
e: Map_Entry(Key, Value);
e.key = key;
e.hash = hasher(&e.key, 0);
e.next = -1;
idx := array_len(m.entries);
array_push(&m.entries, e);
return idx;
}
_map_erase :: proc(m: ^$M/Map, fr: Map_Find_Result) {
if fr.entry_prev < 0 {
array_set(&m.hash, fr.hash_index, array_get(m.entries, fr.entry_index).next);
} else {
array_get_ptr(m.entries, fr.entry_prev).next = array_get(m.entries, fr.entry_index).next;
}
if fr.entry_index == array_len(m.entries)-1 {
array_pop_back(&m.entries);
return;
}
array_set(&m.entries, fr.entry_index, array_get(m.entries, array_len(m.entries)-1));
last := _map_find_key(m^, array_get(m.entries, fr.entry_index).key);
if last.entry_prev < 0 {
array_get_ptr(m.entries, last.entry_prev).next = fr.entry_index;
} else {
array_set(&m.hash, last.hash_index, fr.entry_index);
}
}
_map_find_key :: proc(m: $M/Map($Key, $Value), key: Key) -> Map_Find_Result where intrinsics.type_is_valid_map_key(Key) {
fr: Map_Find_Result;
fr.hash_index = -1;
fr.entry_prev = -1;
fr.entry_index = -1;
if array_len(m.hash) == 0 {
return fr;
}
hasher := intrinsics.type_hasher_proc(Key);
key := key;
hash := hasher(&key, 0);
fr.hash_index = int(hash % uintptr(array_len(m.hash)));
fr.entry_index = array_get(m.hash, fr.hash_index);
for fr.entry_index >= 0 {
it := array_get_ptr(m.entries, fr.entry_index);
if it.hash == hash && it.key == key {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = it.next;
}
return fr;
}
_map_find_entry :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) -> Map_Find_Result {
fr: Map_Find_Result;
fr.hash_index = -1;
fr.entry_prev = -1;
fr.entry_index = -1;
if array_len(m.hash) == 0 {
return fr;
}
fr.hash_index = int(e.hash % uintptr(array_len(m.hash)));
fr.entry_index = array_get(m.hash, fr.hash_index);
for fr.entry_index >= 0 {
it := array_get_ptr(m.entries, fr.entry_index);
if it == e {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = it.next;
}
return fr;
}
_map_find_or_fail :: proc(m: $M/Map($Key, $Value), key: Key) -> int {
return _map_find_key(m, key).entry_index;
}
_map_find_or_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int {
fr := _map_find_key(m^, key);
if fr.entry_index >= 0 {
return fr.entry_index;
}
i := _map_add_entry(m, key);
if fr.entry_prev < 0 {
array_set(&m.hash, fr.hash_index, i);
} else {
array_get_ptr(m.entries, fr.entry_prev).next = i;
}
return i;
}
_map_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int {
fr := _map_find_key(m^, key);
i := _map_add_entry(m, key);
if fr.entry_prev < 0 {
array_set(&m.hash, fr.hash_index, i);
} else {
array_get_ptr(m.entries, fr.entry_prev).next = i;
}
array_get_ptr(m.entries, i).next = fr.entry_index;
return i;
}
_map_full :: proc(m: $M/Map($Key, $Value)) -> bool {
// TODO(bill): Determine good max load factor
return array_len(m.entries) >= (array_len(m.hash) / 4)*3;
}
_map_grow :: proc(m: ^$M/Map($Key, $Value)) {
new_size := array_len(m.entries) * 4 + 7; // TODO(bill): Determine good grow rate
map_reserve(m, new_size);
}
-113
View File
@@ -1,113 +0,0 @@
package container
Priority_Queue :: struct(T: typeid) {
data: Array(T),
len: int,
priority: proc(item: T) -> int,
}
priority_queue_init_none :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, allocator := context.allocator) {
queue_init_len(q, f, 0, allocator);
}
priority_queue_init_len :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, allocator := context.allocator) {
queue_init_len_cap(q, f, 0, 16, allocator);
}
priority_queue_init_len_cap :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, cap: int, allocator := context.allocator) {
array_init(&q.data, len, cap, allocator);
q.len = len;
q.priority = f;
}
priority_queue_init :: proc{priority_queue_init_none, priority_queue_init_len, priority_queue_init_len_cap};
priority_queue_delete :: proc(q: $Q/Priority_Queue($T)) {
array_delete(q.data);
}
priority_queue_clear :: proc(q: ^$Q/Priority_Queue($T)) {
q.len = 0;
}
priority_queue_len :: proc(q: $Q/Priority_Queue($T)) -> int {
return q.len;
}
priority_queue_cap :: proc(q: $Q/Priority_Queue($T)) -> int {
return array_cap(q.data);
}
priority_queue_space :: proc(q: $Q/Priority_Queue($T)) -> int {
return array_len(q.data) - q.len;
}
priority_queue_reserve :: proc(q: ^$Q/Priority_Queue($T), capacity: int) {
if capacity > q.len {
array_resize(&q.data, new_capacity);
}
}
priority_queue_resize :: proc(q: ^$Q/Priority_Queue($T), length: int) {
if length > q.len {
array_resize(&q.data, new_capacity);
}
q.len = length;
}
_priority_queue_grow :: proc(q: ^$Q/Priority_Queue($T), min_capacity: int = 0) {
new_capacity := max(array_len(q.data)*2 + 8, min_capacity);
array_resize(&q.data, new_capacity);
}
priority_queue_push :: proc(q: ^$Q/Priority_Queue($T), item: T) {
if array_len(q.data) - q.len == 0 {
_priority_queue_grow(q);
}
s := array_slice(q.data);
s[q.len] = item;
i := q.len;
for i > 0 {
p := (i - 1) / 2;
if q.priority(s[p]) <= q.priority(item) do break;
s[i] = s[p];
i = p;
}
q.len += 1;
if q.len > 0 do s[i] = item;
}
priority_queue_pop :: proc(q: ^$Q/Priority_Queue($T)) -> T {
assert(q.len > 0);
s := array_slice(q.data);
min := s[0];
root := s[q.len-1];
q.len -= 1;
i := 0;
for i * 2 + 1 < q.len {
a := i * 2 + 1;
b := i * 2 + 2;
c := b < q.len && q.priority(s[b]) < q.priority(s[a]) ? b : a;
if q.priority(s[c]) >= q.priority(root) do break;
s[i] = s[c];
i = c;
}
if q.len > 0 do s[i] = root;
return min;
}
priority_queue_peek :: proc(q: ^$Q/Priority_Queue($T)) -> T {
assert(q.len > 0);
s := array_slice(q.data);
return s[0];
}
@@ -0,0 +1,143 @@
package container_priority_queue
import "core:builtin"
Priority_Queue :: struct($T: typeid) {
queue: [dynamic]T,
less: proc(a, b: T) -> bool,
swap: proc(q: []T, i, j: int),
}
DEFAULT_CAPACITY :: 16
default_swap_proc :: proc($T: typeid) -> proc(q: []T, i, j: int) {
return proc(q: []T, i, j: int) {
q[i], q[j] = q[j], q[i]
}
}
init :: proc(pq: ^$Q/Priority_Queue($T), less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int), capacity := DEFAULT_CAPACITY, allocator := context.allocator) {
if pq.queue.allocator.procedure == nil {
pq.queue.allocator = allocator
}
reserve(pq, capacity)
pq.less = less
pq.swap = swap
}
init_from_dynamic_array :: proc(pq: ^$Q/Priority_Queue($T), queue: [dynamic]T, less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int)) {
pq.queue = queue
pq.less = less
pq.swap = swap
n := builtin.len(pq.queue)
for i := n/2 - 1; i >= 0; i -= 1 {
_shift_down(pq, i, n)
}
}
destroy :: proc(pq: ^$Q/Priority_Queue($T)) {
clear(pq)
delete(pq.queue)
}
reserve :: proc(pq: ^$Q/Priority_Queue($T), capacity: int) {
builtin.reserve(&pq.queue, capacity)
}
clear :: proc(pq: ^$Q/Priority_Queue($T)) {
builtin.clear(&pq.queue)
}
len :: proc(pq: $Q/Priority_Queue($T)) -> int {
return builtin.len(pq.queue)
}
cap :: proc(pq: $Q/Priority_Queue($T)) -> int {
return builtin.cap(pq.queue)
}
_shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool {
// O(n log n)
if 0 > i0 || i0 > n {
return false
}
i := i0
queue := pq.queue[:]
for {
j1 := 2*i + 1
if j1 < 0 || j1 >= n {
break
}
j := j1
if j2 := j1+1; j2 < n && pq.less(queue[j2], queue[j1]) {
j = j2
}
if !pq.less(queue[j], queue[i]) {
break
}
pq.swap(queue, i, j)
i = j
}
return i > i0
}
_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) {
j := j
queue := pq.queue[:]
n := builtin.len(queue)
for 0 <= j {
i := (j-1)/2
if i == j || !pq.less(queue[j], queue[i]) {
break
}
pq.swap(queue, i, j)
j = i
}
}
// NOTE(bill): When an element at index 'i' has changed its value, this will fix the
// the heap ordering. This is using a basic "heapsort" with shift up and a shift down parts.
fix :: proc(pq: ^$Q/Priority_Queue($T), i: int) {
if !_shift_down(pq, i, builtin.len(pq.queue)) {
_shift_up(pq, i)
}
}
push :: proc(pq: ^$Q/Priority_Queue($T), value: T) {
append(&pq.queue, value)
_shift_up(pq, builtin.len(pq.queue)-1)
}
pop :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T) {
assert(condition=builtin.len(pq.queue)>0, loc=loc)
n := builtin.len(pq.queue)-1
pq.swap(pq.queue[:], 0, n)
_shift_down(pq, 0, n)
return builtin.pop(&pq.queue)
}
pop_safe :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T, ok: bool) {
if builtin.len(pq.queue) > 0 {
n := builtin.len(pq.queue)-1
pq.swap(pq.queue[:], 0, n)
_shift_down(pq, 0, n)
return builtin.pop_safe(&pq.queue)
}
return
}
remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) {
n := builtin.len(pq.queue)
if 0 <= i && i < n {
if n != i {
pq.swap(pq.queue[:], i, n)
_shift_down(pq, i, n)
_shift_up(pq, i)
}
value, ok = builtin.pop_safe(&pq.queue)
}
return
}
-175
View File
@@ -1,175 +0,0 @@
package container
Queue :: struct(T: typeid) {
data: Array(T),
len: int,
offset: int,
}
/*
queue_init :: proc{
queue_init_none,
queue_init_len,
queue_init_len_cap,
}
queue_delete
queue_clear
queue_len
queue_cap
queue_space
queue_get
queue_set
queue_reserve
queue_resize
queue_push :: proc{
queue_push_back,
queue_push_elems,
};
queue_push_front
queue_pop_front
queue_pop_back
queue_consume
*/
queue_init_none :: proc(q: ^$Q/Queue($T), allocator := context.allocator) {
queue_init_len(q, 0, allocator);
}
queue_init_len :: proc(q: ^$Q/Queue($T), len: int, allocator := context.allocator) {
queue_init_len_cap(q, 0, 16, allocator);
}
queue_init_len_cap :: proc(q: ^$Q/Queue($T), len: int, cap: int, allocator := context.allocator) {
array_init(&q.data, len, cap, allocator);
q.len = len;
q.offset = 0;
}
queue_init :: proc{queue_init_none, queue_init_len, queue_init_len_cap};
queue_delete :: proc(q: $Q/Queue($T)) {
array_delete(q.data);
}
queue_clear :: proc(q: ^$Q/Queue($T)) {
q.len = 0;
}
queue_len :: proc(q: $Q/Queue($T)) -> int {
return q.len;
}
queue_cap :: proc(q: $Q/Queue($T)) -> int {
return array_cap(q.data);
}
queue_space :: proc(q: $Q/Queue($T)) -> int {
return array_len(q.data) - q.len;
}
queue_get :: proc(q: $Q/Queue($T), index: int) -> T {
i := (index + q.offset) % array_len(q.data);
data := array_slice(q.data);
return data[i];
}
queue_set :: proc(q: ^$Q/Queue($T), index: int, item: T) {
i := (index + q.offset) % array_len(q.data);
data := array_slice(q.data);
data[i] = item;
}
queue_reserve :: proc(q: ^$Q/Queue($T), capacity: int) {
if capacity > q.len {
_queue_increase_capacity(q, capacity);
}
}
queue_resize :: proc(q: ^$Q/Queue($T), length: int) {
if length > q.len {
_queue_increase_capacity(q, length);
}
q.len = length;
}
queue_push_back :: proc(q: ^$Q/Queue($T), item: T) {
if queue_space(q^) == 0 {
_queue_grow(q);
}
queue_set(q, q.len, item);
q.len += 1;
}
queue_push_front :: proc(q: ^$Q/Queue($T), item: T) {
if queue_space(q^) == 0 {
_queue_grow(q);
}
q.offset = (q.offset - 1 + array_len(q.data)) % array_len(q.data);
q.len += 1;
queue_set(q, 0, item);
}
queue_pop_front :: proc(q: ^$Q/Queue($T)) -> T {
assert(q.len > 0);
item := queue_get(q^, 0);
q.offset = (q.offset + 1) % array_len(q.data);
q.len -= 1;
if q.len == 0 {
q.offset = 0;
}
return item;
}
queue_pop_back :: proc(q: ^$Q/Queue($T)) -> T {
assert(q.len > 0);
item := queue_get(q^, q.len-1);
q.len -= 1;
return item;
}
queue_consume :: proc(q: ^$Q/Queue($T), count: int) {
q.offset = (q.offset + count) & array_len(q.data);
q.len -= count;
}
queue_push_elems :: proc(q: ^$Q/Queue($T), items: ..T) {
if queue_space(q^) < len(items) {
_queue_grow(q, q.len + len(items));
}
size := array_len(q.data);
insert := (q.offset + q.len) % size;
to_insert := len(items);
if insert + to_insert > size {
to_insert = size - insert;
}
the_items := items[:];
data := array_slice(q.data);
q.len += copy(data[insert:][:to_insert], the_items);
the_items = the_items[to_insert:];
q.len += copy(data[:], the_items);
}
queue_push :: proc{queue_push_back, queue_push_elems};
_queue_increase_capacity :: proc(q: ^$Q/Queue($T), new_capacity: int) {
end := array_len(q.data);
array_resize(&q.data, new_capacity);
if q.offset + q.len > end {
end_items := q.len + end;
data := array_slice(q.data);
copy(data[new_capacity-end_items:][:end_items], data[q.offset:][:end_items]);
q.offset += new_capacity - end;
}
}
_queue_grow :: proc(q: ^$Q/Queue($T), min_capacity: int = 0) {
new_capacity := max(array_len(q.data)*2 + 8, min_capacity);
_queue_increase_capacity(q, new_capacity);
}
+209
View File
@@ -0,0 +1,209 @@
package container_queue
import "core:builtin"
import "core:runtime"
_ :: runtime
// Dynamically resizable double-ended queue/ring-buffer
Queue :: struct($T: typeid) {
data: [dynamic]T,
len: uint,
offset: uint,
}
DEFAULT_CAPACITY :: 16
// Procedure to initialize a queue
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool {
if q.data.allocator.procedure == nil {
q.data.allocator = allocator
}
clear(q)
return reserve(q, capacity)
}
// Procedure to initialize a queue from a fixed backing slice
init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool {
clear(q)
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
data = raw_data(backing),
len = builtin.len(backing),
cap = builtin.len(backing),
allocator = {procedure=runtime.nil_allocator_proc, data=nil},
}
return true
}
// Procedure to destroy a queue
destroy :: proc(q: ^$Q/Queue($T)) {
delete(q.data)
}
// The length of the queue
len :: proc(q: $Q/Queue($T)) -> int {
return int(q.len)
}
// The current capacity of the queue
cap :: proc(q: $Q/Queue($T)) -> int {
return builtin.len(q.data)
}
// Remaining space in the queue (cap-len)
space :: proc(q: $Q/Queue($T)) -> int {
return builtin.len(q.data) - int(q.len)
}
// Reserve enough space for at least the specified capacity
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool {
if uint(capacity) > q.len {
return _grow(q, uint(capacity))
}
return true
}
get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
idx := (uint(i)+q.offset)%builtin.len(q.data)
return q.data[idx]
}
set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
idx := (uint(i)+q.offset)%builtin.len(q.data)
q.data[idx] = val
}
get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^T {
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
idx := (uint(i)+q.offset)%builtin.len(q.data)
return &q.data[idx]
}
// Push an element to the back of the queue
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
if space(q^) == 0 {
_grow(q) or_return
}
idx := (q.offset+uint(q.len))%builtin.len(q.data)
q.data[idx] = elem
q.len += 1
return true
}
// Push an element to the front of the queue
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
if space(q^) == 0 {
_grow(q) or_return
}
q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
q.len += 1
q.data[q.offset] = elem
return true
}
// Pop an element from the back of the queue
pop_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
assert(condition=q.len > 0, loc=loc)
q.len -= 1
idx := (q.offset+uint(q.len))%builtin.len(q.data)
elem = q.data[idx]
return
}
// Safely pop an element from the back of the queue
pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
if q.len > 0 {
q.len -= 1
idx := (q.offset+uint(q.len))%builtin.len(q.data)
elem = q.data[idx]
ok = true
}
return
}
// Pop an element from the front of the queue
pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
assert(condition=q.len > 0, loc=loc)
elem = q.data[q.offset]
q.offset = (q.offset+1)%builtin.len(q.data)
q.len -= 1
return
}
// Safely pop an element from the front of the queue
pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
if q.len > 0 {
elem = q.data[q.offset]
q.offset = (q.offset+1)%builtin.len(q.data)
q.len -= 1
ok = true
}
return
}
// Push multiple elements to the front of the queue
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
n := uint(builtin.len(elems))
if space(q^) < int(n) {
_grow(q, q.len + n) or_return
}
sz := uint(builtin.len(q.data))
insert_from := (q.offset + q.len) % sz
insert_to := n
if insert_from + insert_to > sz {
insert_to = sz - insert_from
}
copy(q.data[insert_from:], elems[:insert_to])
copy(q.data[:insert_from], elems[insert_to:])
q.len += n
return true
}
// Consume `n` elements from the front of the queue
consume_front :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) {
assert(condition=int(q.len) >= n, loc=loc)
if n > 0 {
nu := uint(n)
q.offset = (q.offset + nu) % builtin.len(q.data)
q.len -= nu
}
}
// Consume `n` elements from the back of the queue
consume_back :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) {
assert(condition=int(q.len) >= n, loc=loc)
if n > 0 {
q.len -= uint(n)
}
}
append_elem :: push_back
append_elems :: push_back_elems
push :: proc{push_back, push_back_elems}
append :: proc{push_back, push_back_elems}
// Clear the contents of the queue
clear :: proc(q: ^$Q/Queue($T)) {
q.len = 0
q.offset = 0
}
// Internal growinh procedure
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
n := uint(builtin.len(q.data))
builtin.resize(&q.data, int(new_capacity)) or_return
if q.offset + q.len > n {
diff := n - q.offset
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
q.offset += new_capacity - n
}
return true
}
-73
View File
@@ -1,73 +0,0 @@
package container
Ring :: struct(T: typeid) {
next, prev: ^Ring(T),
value: T,
}
ring_init :: proc(r: ^$R/Ring) -> ^R {
r.prev, r.next = r, r;
return r;
}
ring_next :: proc(r: ^$R/Ring) -> ^R {
if r.next == nil {
return ring_init(r);
}
return r.next;
}
ring_prev :: proc(r: ^$R/Ring) -> ^R {
if r.prev == nil {
return ring_init(r);
}
return r.prev;
}
ring_move :: proc(r: ^$R/Ring, n: int) -> ^R {
if r.next == nil {
return ring_init(r);
}
switch {
case n < 0:
for _ in n..<0 {
r = r.prev;
}
case n > 0:
for _ in 0..<n {
r = r.next;
}
}
return r;
}
ring_link :: proc(r, s: ^$R/Ring) -> ^R {
n := ring_next(r);
if s != nil {
p := ring_prev(s);
r.next = s;
s.prev = r;
n.prev = p;
p.next = n;
}
return n;
}
ring_unlink :: proc(r: ^$R/Ring, n: int) -> ^R {
if n <= 0 {
return nil;
}
return ring_link(r, ring_move(r, n+1));
}
ring_len :: proc(r: ^$R/Ring) -> int {
n := 0;
if r != nil {
n = 1;
for p := ring_next(&p); p != r; p = p.next {
n += 1;
}
}
return n;
}
-240
View File
@@ -1,240 +0,0 @@
package container
Set :: struct {
hash: Array(int),
entries: Array(Set_Entry),
}
Set_Entry :: struct {
key: u64,
next: int,
}
/*
set_init :: proc{
set_init_none,
set_init_cap,
}
set_delete
set_in
set_not_in
set_add
set_remove
set_reserve
set_clear
*/
set_init :: proc{set_init_none, set_init_cap};
set_init_none :: proc(m: ^Set, allocator := context.allocator) {
m.hash.allocator = allocator;
m.entries.allocator = allocator;
}
set_init_cap :: proc(m: ^Set, cap: int, allocator := context.allocator) {
m.hash.allocator = allocator;
m.entries.allocator = allocator;
set_reserve(m, cap);
}
set_delete :: proc(m: Set) {
array_delete(m.hash);
array_delete(m.entries);
}
set_in :: proc(m: Set, key: u64) -> bool {
return _set_find_or_fail(m, key) >= 0;
}
set_not_in :: proc(m: Set, key: u64) -> bool {
return _set_find_or_fail(m, key) < 0;
}
set_add :: proc(m: ^Set, key: u64) {
if array_len(m.hash) == 0 {
_set_grow(m);
}
_ = _set_find_or_make(m, key);
if _set_full(m^) {
_set_grow(m);
}
}
set_remove :: proc(m: ^Set, key: u64) {
fr := _set_find_key(m^, key);
if fr.entry_index >= 0 {
_set_erase(m, fr);
}
}
set_reserve :: proc(m: ^Set, new_size: int) {
nm: Set;
set_init(&nm, m.hash.allocator);
array_resize(&nm.hash, new_size);
array_reserve(&nm.entries, array_len(m.entries));
for i in 0..<new_size {
array_set(&nm.hash, i, -1);
}
for i in 0..<array_len(m.entries) {
e := array_get(m.entries, i);
set_add(&nm, e.key);
}
set_delete(m^);
m^ = nm;
}
set_clear :: proc(m: ^Set) {
array_clear(&m.hash);
array_clear(&m.entries);
}
set_equal :: proc(a, b: Set) -> bool {
a_entries := array_slice(a.entries);
b_entries := array_slice(b.entries);
if len(a_entries) != len(b_entries) {
return false;
}
for e in a_entries {
if set_not_in(b, e.key) {
return false;
}
}
return true;
}
/// Internal
_set_add_entry :: proc(m: ^Set, key: u64) -> int {
e: Set_Entry;
e.key = key;
e.next = -1;
idx := array_len(m.entries);
array_push(&m.entries, e);
return idx;
}
_set_erase :: proc(m: ^Set, fr: Map_Find_Result) {
if fr.entry_prev < 0 {
array_set(&m.hash, fr.hash_index, array_get(m.entries, fr.entry_index).next);
} else {
array_get_ptr(m.entries, fr.entry_prev).next = array_get(m.entries, fr.entry_index).next;
}
if fr.entry_index == array_len(m.entries)-1 {
array_pop_back(&m.entries);
return;
}
array_set(&m.entries, fr.entry_index, array_get(m.entries, array_len(m.entries)-1));
last := _set_find_key(m^, array_get(m.entries, fr.entry_index).key);
if last.entry_prev < 0 {
array_get_ptr(m.entries, last.entry_prev).next = fr.entry_index;
} else {
array_set(&m.hash, last.hash_index, fr.entry_index);
}
}
_set_find_key :: proc(m: Set, key: u64) -> Map_Find_Result {
fr: Map_Find_Result;
fr.hash_index = -1;
fr.entry_prev = -1;
fr.entry_index = -1;
if array_len(m.hash) == 0 {
return fr;
}
fr.hash_index = int(key % u64(array_len(m.hash)));
fr.entry_index = array_get(m.hash, fr.hash_index);
for fr.entry_index >= 0 {
it := array_get_ptr(m.entries, fr.entry_index);
if it.key == key {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = it.next;
}
return fr;
}
_set_find_entry :: proc(m: ^Set, e: ^Set_Entry) -> Map_Find_Result {
fr: Map_Find_Result;
fr.hash_index = -1;
fr.entry_prev = -1;
fr.entry_index = -1;
if array_len(m.hash) == 0 {
return fr;
}
fr.hash_index = int(e.key % u64(array_len(m.hash)));
fr.entry_index = array_get(m.hash, fr.hash_index);
for fr.entry_index >= 0 {
it := array_get_ptr(m.entries, fr.entry_index);
if it == e {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = it.next;
}
return fr;
}
_set_find_or_fail :: proc(m: Set, key: u64) -> int {
return _set_find_key(m, key).entry_index;
}
_set_find_or_make :: proc(m: ^Set, key: u64) -> int {
fr := _set_find_key(m^, key);
if fr.entry_index >= 0 {
return fr.entry_index;
}
i := _set_add_entry(m, key);
if fr.entry_prev < 0 {
array_set(&m.hash, fr.hash_index, i);
} else {
array_get_ptr(m.entries, fr.entry_prev).next = i;
}
return i;
}
_set_make :: proc(m: ^Set, key: u64) -> int {
fr := _set_find_key(m^, key);
i := _set_add_entry(m, key);
if fr.entry_prev < 0 {
array_set(&m.hash, fr.hash_index, i);
} else {
array_get_ptr(m.entries, fr.entry_prev).next = i;
}
array_get_ptr(m.entries, i).next = fr.entry_index;
return i;
}
_set_full :: proc(m: Set) -> bool {
// TODO(bill): Determine good max load factor
return array_len(m.entries) >= (array_len(m.hash) / 4)*3;
}
_set_grow :: proc(m: ^Set) {
new_size := array_len(m.entries) * 4 + 7; // TODO(bill): Determine good grow rate
set_reserve(m, new_size);
}
-95
View File
@@ -1,95 +0,0 @@
package container
Small_Array :: struct(N: int, T: typeid) where N >= 0 {
data: [N]T,
len: int,
}
small_array_len :: proc(a: $A/Small_Array) -> int {
return a.len;
}
small_array_cap :: proc(a: $A/Small_Array) -> int {
return len(a.data);
}
small_array_space :: proc(a: $A/Small_Array) -> int {
return len(a.data) - a.len;
}
small_array_slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
return a.data[:a.len];
}
small_array_get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T {
return a.data[index];
}
small_array_get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T {
return &a.data[index];
}
small_array_set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) {
a.data[index] = item;
}
small_array_resize :: proc(a: ^$A/Small_Array, length: int) {
a.len = min(length, len(a.data));
}
small_array_push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
if a.len < len(a.data) {
a.len += 1;
a.data[a.len-1] = item;
return true;
}
return false;
}
small_array_push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
if a.len < len(a.data) {
a.len += 1;
data := small_array_slice(a);
copy(data[1:], data[:]);
data[0] = item;
return true;
}
return false;
}
small_array_pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
assert(condition=a.len > 0, loc=loc);
item := a.data[a.len-1];
a.len -= 1;
return item;
}
small_array_pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
assert(condition=a.len > 0, loc=loc);
item := a.data[0];
s := small_array_slice(a);
copy(s[:], s[1:]);
a.len -= 1;
return item;
}
small_array_consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) {
assert(condition=a.len >= count, loc=loc);
a.len -= count;
}
small_array_clear :: proc(a: ^$A/Small_Array($N, $T)) {
small_array_resize(a, 0);
}
small_array_push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
n := copy(a.data[a.len:], items[:]);
a.len += n;
}
small_array_push :: proc{small_array_push_back, small_array_push_back_elems};
small_array_append :: proc{small_array_push_back, small_array_push_back_elems};
+117
View File
@@ -0,0 +1,117 @@
package container_small_array
import "core:builtin"
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
data: [N]T,
len: int,
}
len :: proc(a: $A/Small_Array) -> int {
return a.len
}
cap :: proc(a: $A/Small_Array) -> int {
return builtin.len(a.data)
}
space :: proc(a: $A/Small_Array) -> int {
return builtin.len(a.data) - a.len
}
slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
return a.data[:a.len]
}
get :: proc(a: $A/Small_Array($N, $T), index: int) -> T {
return a.data[index]
}
get_ptr :: proc(a: ^$A/Small_Array($N, $T), index: int) -> ^T {
return &a.data[index]
}
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T) {
a.data[index] = item
}
resize :: proc(a: ^$A/Small_Array, length: int) {
a.len = min(length, builtin.len(a.data))
}
push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
if a.len < cap(a^) {
a.data[a.len] = item
a.len += 1
return true
}
return false
}
push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool {
if a.len < cap(a^) {
a.len += 1
data := slice(a)
copy(data[1:], data[:])
data[0] = item
return true
}
return false
}
pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
assert(condition=(N > 0 && a.len > 0), loc=loc)
item := a.data[a.len-1]
a.len -= 1
return item
}
pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T {
assert(condition=(N > 0 && a.len > 0), loc=loc)
item := a.data[0]
s := slice(a)
copy(s[:], s[1:])
a.len -= 1
return item
}
pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
if N > 0 && a.len > 0 {
item = a.data[a.len-1]
a.len -= 1
ok = true
}
return
}
pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) {
if N > 0 && a.len > 0 {
item = a.data[0]
s := slice(a)
copy(s[:], s[1:])
a.len -= 1
ok = true
}
return
}
consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) {
assert(condition=a.len >= count, loc=loc)
a.len -= count
}
clear :: proc(a: ^$A/Small_Array($N, $T)) {
resize(a, 0)
}
push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) {
n := copy(a.data[a.len:], items[:])
a.len += n
}
append_elem :: push_back
append_elems :: push_back_elems
push :: proc{push_back, push_back_elems}
append :: proc{push_back, push_back_elems}
@@ -0,0 +1,98 @@
// The following is a generic O(V+E) topological sorter implementation.
// This is the fastest known method for topological sorting and Odin's
// map type is being used to accelerate lookups.
package container_topological_sort
import "core:intrinsics"
import "core:runtime"
_ :: intrinsics
_ :: runtime
Relations :: struct($K: typeid) where intrinsics.type_is_valid_map_key(K) {
dependents: map[K]bool,
dependencies: int,
}
Sorter :: struct(K: typeid) where intrinsics.type_is_valid_map_key(K) {
relations: map[K]Relations(K),
dependents_allocator: runtime.Allocator,
}
@(private="file")
make_relations :: proc(sorter: ^$S/Sorter($K)) -> (r: Relations(K)) {
r.dependents.allocator = sorter.dependents_allocator
return
}
init :: proc(sorter: ^$S/Sorter($K)) {
sorter.relations = make(map[K]Relations(K))
sorter.dependents_allocator = context.allocator
}
destroy :: proc(sorter: ^$S/Sorter($K)) {
for _, v in &sorter.relations {
delete(v.dependents)
}
delete(sorter.relations)
}
add_key :: proc(sorter: ^$S/Sorter($K), key: K) -> bool {
if key in sorter.relations {
return false
}
sorter.relations[key] = make_relations(sorter)
return true
}
add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool {
if key == dependency {
return false
}
find := &sorter.relations[dependency]
if find == nil {
find = map_insert(&sorter.relations, dependency, make_relations(sorter))
}
if find.dependents[key] {
return true
}
find.dependents[key] = true
find = &sorter.relations[key]
if find == nil {
find = map_insert(&sorter.relations, key, make_relations(sorter))
}
find.dependencies += 1
return true
}
sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) {
relations := &sorter.relations
for k, v in relations {
if v.dependencies == 0 {
append(&sorted, k)
}
}
for root in &sorted do for k, _ in relations[root].dependents {
relation := &relations[k]
relation.dependencies -= 1
if relation.dependencies == 0 {
append(&sorted, k)
}
}
for k, v in relations {
if v.dependencies != 0 {
append(&cycled, k)
}
}
return
}
+95
View File
@@ -0,0 +1,95 @@
# crypto
A crypto library for the Odin language
## Supported
This library offers various algorithms implemented in Odin.
Please see the chart below for the options.
## Hashing algorithms
| Algorithm | |
|:-------------------------------------------------------------------------------------------------------------|:-----------------|
| [BLAKE](https://web.archive.org/web/20190915215948/https://131002.net/blake) | &#10004;&#65039; |
| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | &#10004;&#65039; |
| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | &#10004;&#65039; |
| [GOST](https://datatracker.ietf.org/doc/html/rfc5831) | &#10004;&#65039; |
| [Grøstl](http://www.groestl.info/Groestl.zip) | &#10004;&#65039; |
| [HAVAL](https://web.archive.org/web/20150111210116/http://labs.calyptix.com/haval.php) | &#10004;&#65039; |
| [JH](https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html) | &#10004;&#65039; |
| [Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | &#10004;&#65039; |
| [MD2](https://datatracker.ietf.org/doc/html/rfc1319) | &#10004;&#65039; |
| [MD4](https://datatracker.ietf.org/doc/html/rfc1320) | &#10004;&#65039; |
| [MD5](https://datatracker.ietf.org/doc/html/rfc1321) | &#10004;&#65039; |
| [RIPEMD](https://homes.esat.kuleuven.be/~bosselae/ripemd160.html) | &#10004;&#65039; |
| [SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | &#10004;&#65039; |
| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | &#10004;&#65039; |
| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | &#10004;&#65039; |
| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | &#10004;&#65039; |
| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | &#10004;&#65039; |
| [Streebog](https://datatracker.ietf.org/doc/html/rfc6986) | &#10004;&#65039; |
| [Tiger](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | &#10004;&#65039; |
| [Tiger2](https://www.cs.technion.ac.il/~biham/Reports/Tiger/) | &#10004;&#65039; |
| [Whirlpool](https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html) | &#10004;&#65039; |
#### High level API
Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*.
Included in these groups are six procedures.
* `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally
* `hash_bytes` - Hash a given byte slice and return the computed hash
* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally
* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash
* `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it
* `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true)
\* On some algorithms there is another part to the name, since they might offer control about additional parameters.
For instance, `HAVAL` offers different sizes as well as three different round amounts.
Computing a 256-bit hash with 3 rounds is therefore achieved by calling `haval.hash_256_3(...)`.
#### Low level API
The above mentioned procedures internally call three procedures: `init`, `update` and `final`.
You may also directly call them, if you wish.
#### Example
```odin
package crypto_example
// Import the desired package
import "core:crypto/md4"
main :: proc() {
input := "foo"
// Compute the hash, using the high level API
computed_hash := md4.hash(input)
// Variant that takes a destination buffer, instead of returning the computed hash
hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash
md4.hash(input, hash[:])
// Compute the hash, using the low level API
ctx: md4.Md4_Context
computed_hash_low: [16]byte
md4.init(&ctx)
md4.update(&ctx, transmute([]byte)input)
md4.final(&ctx, computed_hash_low[:])
}
```
For example uses of all available algorithms, please see the tests within `tests/core/crypto`.
#### Thread safety
The crypto package is not thread-safe at the moment. This may change in the future.
### Disclaimer
The algorithms were ported out of curiosity and due to interest in the field.
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
Whereever we were able to find official test vectors, those were used to verify the implementation.
We do not recommend using them in a production environment, without any additional testing and/or verification.
### ToDo
* Ciphers (Symmetric, Asymmetric)
* MACs (Message Authentication Code)
* CSPRNGs (Cryptographically Secure PseudoRandom Number Generator)
* KDFs (Key Derivation Function)
* KEAs (Key Exchange Algorithm)
### License
This library is made available under the BSD-3 license.
File diff suppressed because it is too large Load Diff
+35
View File
@@ -0,0 +1,35 @@
# fiat
This package contains low level arithmetic required to implement certain
cryptographic primitives, ported from the [fiat-crypto project][1]
along with some higher-level helpers.
## Notes
fiat-crypto gives the choice of 3 licenses for derived works. The 1-Clause
BSD license is chosen as it is compatible with Odin's existing licensing.
The routines are intended to be timing-safe, as long as the underlying
integer arithmetic is constant time. This is true on most systems commonly
used today, with the notable exception of WASM.
While fiat-crypto provides both output targeting both 32-bit and 64-bit
architectures, only the 64-bit versions were used, as 32-bit architectures
are becoming increasingly uncommon and irrelevant.
With the current Odin syntax, the Go output is trivially ported in most
cases and was used as the basis of the port.
In the future, it would be better to auto-generate Odin either directly
by adding an appropriate code-gen backend written in Coq, or perhaps by
parsing the JSON output.
As this is a port rather than autogenerated output, none of fiat-crypto's
formal verification guarantees apply, unless it is possible to prove binary
equivalence.
For the most part, alterations to the base fiat-crypto generated code was
kept to a minimum, to aid auditability. This results in a somewhat
ideosyncratic style, and in some cases minor performance penalties.
[1]: https://github.com/mit-plv/fiat-crypto
+24
View File
@@ -0,0 +1,24 @@
package fiat
// This package provides various helpers and types common to all of the
// fiat-crypto derived backends.
// This code only works on a two's complement system.
#assert((-1 & 3) == 3)
u1 :: distinct u8
i1 :: distinct i8
cmovznz_u64 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) {
x1 := (u64(arg1) * 0xffffffffffffffff)
x2 := ((x1 & arg3) | ((~x1) & arg2))
out1 = x2
return
}
cmovznz_u32 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) {
x1 := (u32(arg1) * 0xffffffff)
x2 := ((x1 & arg3) | ((~x1) & arg2))
out1 = x2
return
}
@@ -0,0 +1,138 @@
package field_curve25519
import "core:crypto"
import "core:mem"
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element {
return transmute(^Loose_Field_Element)(arg1)
}
fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element {
return transmute(^Tight_Field_Element)(arg1)
}
fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
// Ignore the unused bit by copying the input and masking the bit off
// prior to deserialization.
tmp1: [32]byte = ---
copy_slice(tmp1[:], arg1[:])
tmp1[31] &= 127
_fe_from_bytes(out1, &tmp1)
mem.zero_explicit(&tmp1, size_of(tmp1))
}
fe_equal :: proc "contextless" (arg1, arg2: ^Tight_Field_Element) -> int {
tmp2: [32]byte = ---
fe_to_bytes(&tmp2, arg2)
ret := fe_equal_bytes(arg1, &tmp2)
mem.zero_explicit(&tmp2, size_of(tmp2))
return ret
}
fe_equal_bytes :: proc "contextless" (arg1: ^Tight_Field_Element, arg2: ^[32]byte) -> int {
tmp1: [32]byte = ---
fe_to_bytes(&tmp1, arg1)
ret := crypto.compare_constant_time(tmp1[:], arg2[:])
mem.zero_explicit(&tmp1, size_of(tmp1))
return ret
}
fe_carry_pow2k :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element, arg2: uint) {
// Special case: `arg1^(2 * 0) = 1`, though this should never happen.
if arg2 == 0 {
fe_one(out1)
return
}
fe_carry_square(out1, arg1)
for _ in 1..<arg2 {
fe_carry_square(out1, fe_relax_cast(out1))
}
}
fe_carry_opp :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
fe_opp(fe_relax_cast(out1), arg1)
fe_carry(out1, fe_relax_cast(out1))
}
fe_carry_invsqrt :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) -> int {
// Inverse square root taken from Monocypher.
tmp1, tmp2, tmp3: Tight_Field_Element = ---, ---, ---
// t0 = x^((p-5)/8)
// Can be achieved with a simple double & add ladder,
// but it would be slower.
fe_carry_pow2k(&tmp1, arg1, 1)
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 2)
fe_carry_mul(&tmp2, arg1, fe_relax_cast(&tmp2))
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), fe_relax_cast(&tmp2))
fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 1)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 5)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 10)
fe_carry_mul(&tmp2, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp3, fe_relax_cast(&tmp2), 20)
fe_carry_mul(&tmp2, fe_relax_cast(&tmp3), fe_relax_cast(&tmp2))
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 10)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 50)
fe_carry_mul(&tmp2, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp3, fe_relax_cast(&tmp2), 100)
fe_carry_mul(&tmp2, fe_relax_cast(&tmp3), fe_relax_cast(&tmp2))
fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 50)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1))
fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 2)
fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), arg1)
// quartic = x^((p-1)/4)
quartic := &tmp2
fe_carry_square(quartic, fe_relax_cast(&tmp1))
fe_carry_mul(quartic, fe_relax_cast(quartic), arg1)
// Serialize quartic once to save on repeated serialization/sanitization.
quartic_buf: [32]byte = ---
fe_to_bytes(&quartic_buf, quartic)
check := &tmp3
fe_one(check)
p1 := fe_equal_bytes(check, &quartic_buf)
fe_carry_opp(check, check)
m1 := fe_equal_bytes(check, &quartic_buf)
fe_carry_opp(check, &SQRT_M1)
ms := fe_equal_bytes(check, &quartic_buf)
// if quartic == -1 or sqrt(-1)
// then isr = x^((p-1)/4) * sqrt(-1)
// else isr = x^((p-1)/4)
fe_carry_mul(out1, fe_relax_cast(&tmp1), fe_relax_cast(&SQRT_M1))
fe_cond_assign(out1, &tmp1, (m1|ms) ~ 1)
mem.zero_explicit(&tmp1, size_of(tmp1))
mem.zero_explicit(&tmp2, size_of(tmp2))
mem.zero_explicit(&tmp3, size_of(tmp3))
mem.zero_explicit(&quartic_buf, size_of(quartic_buf))
return p1 | m1
}
fe_carry_inv :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
tmp1: Tight_Field_Element
fe_carry_square(&tmp1, arg1)
_ = fe_carry_invsqrt(&tmp1, fe_relax_cast(&tmp1))
fe_carry_square(&tmp1, fe_relax_cast(&tmp1))
fe_carry_mul(out1, fe_relax_cast(&tmp1), arg1)
mem.zero_explicit(&tmp1, size_of(tmp1))
}
@@ -0,0 +1,616 @@
// The BSD 1-Clause License (BSD-1-Clause)
//
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package field_curve25519
// The file provides arithmetic on the field Z/(2^255-19) using
// unsaturated 64-bit integer arithmetic. It is derived primarily
// from the machine generated Golang output from the fiat-crypto project.
//
// While the base implementation is provably correct, this implementation
// makes no such claims as the port and optimizations were done by hand.
// At some point, it may be worth adding support to fiat-crypto for
// generating Odin output.
//
// TODO:
// * When fiat-crypto supports it, using a saturated 64-bit limbs
// instead of 51-bit limbs will be faster, though the gains are
// minimal unless adcx/adox/mulx are used.
import fiat "core:crypto/_fiat"
import "core:math/bits"
Loose_Field_Element :: distinct [5]u64
Tight_Field_Element :: distinct [5]u64
SQRT_M1 := Tight_Field_Element{
1718705420411056,
234908883556509,
2233514472574048,
2117202627021982,
765476049583133,
}
_addcarryx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
x1 := ((u64(arg1) + arg2) + arg3)
x2 := (x1 & 0x7ffffffffffff)
x3 := fiat.u1((x1 >> 51))
out1 = x2
out2 = x3
return
}
_subborrowx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
x2 := fiat.i1((x1 >> 51))
x3 := (u64(x1) & 0x7ffffffffffff)
out1 = x3
out2 = (0x0 - fiat.u1(x2))
return
}
fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) {
x2, x1 := bits.mul_u64(arg1[4], (arg2[4] * 0x13))
x4, x3 := bits.mul_u64(arg1[4], (arg2[3] * 0x13))
x6, x5 := bits.mul_u64(arg1[4], (arg2[2] * 0x13))
x8, x7 := bits.mul_u64(arg1[4], (arg2[1] * 0x13))
x10, x9 := bits.mul_u64(arg1[3], (arg2[4] * 0x13))
x12, x11 := bits.mul_u64(arg1[3], (arg2[3] * 0x13))
x14, x13 := bits.mul_u64(arg1[3], (arg2[2] * 0x13))
x16, x15 := bits.mul_u64(arg1[2], (arg2[4] * 0x13))
x18, x17 := bits.mul_u64(arg1[2], (arg2[3] * 0x13))
x20, x19 := bits.mul_u64(arg1[1], (arg2[4] * 0x13))
x22, x21 := bits.mul_u64(arg1[4], arg2[0])
x24, x23 := bits.mul_u64(arg1[3], arg2[1])
x26, x25 := bits.mul_u64(arg1[3], arg2[0])
x28, x27 := bits.mul_u64(arg1[2], arg2[2])
x30, x29 := bits.mul_u64(arg1[2], arg2[1])
x32, x31 := bits.mul_u64(arg1[2], arg2[0])
x34, x33 := bits.mul_u64(arg1[1], arg2[3])
x36, x35 := bits.mul_u64(arg1[1], arg2[2])
x38, x37 := bits.mul_u64(arg1[1], arg2[1])
x40, x39 := bits.mul_u64(arg1[1], arg2[0])
x42, x41 := bits.mul_u64(arg1[0], arg2[4])
x44, x43 := bits.mul_u64(arg1[0], arg2[3])
x46, x45 := bits.mul_u64(arg1[0], arg2[2])
x48, x47 := bits.mul_u64(arg1[0], arg2[1])
x50, x49 := bits.mul_u64(arg1[0], arg2[0])
x51, x52 := bits.add_u64(x13, x7, u64(0x0))
x53, _ := bits.add_u64(x14, x8, u64(fiat.u1(x52)))
x55, x56 := bits.add_u64(x17, x51, u64(0x0))
x57, _ := bits.add_u64(x18, x53, u64(fiat.u1(x56)))
x59, x60 := bits.add_u64(x19, x55, u64(0x0))
x61, _ := bits.add_u64(x20, x57, u64(fiat.u1(x60)))
x63, x64 := bits.add_u64(x49, x59, u64(0x0))
x65, _ := bits.add_u64(x50, x61, u64(fiat.u1(x64)))
x67 := ((x63 >> 51) | ((x65 << 13) & 0xffffffffffffffff))
x68 := (x63 & 0x7ffffffffffff)
x69, x70 := bits.add_u64(x23, x21, u64(0x0))
x71, _ := bits.add_u64(x24, x22, u64(fiat.u1(x70)))
x73, x74 := bits.add_u64(x27, x69, u64(0x0))
x75, _ := bits.add_u64(x28, x71, u64(fiat.u1(x74)))
x77, x78 := bits.add_u64(x33, x73, u64(0x0))
x79, _ := bits.add_u64(x34, x75, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x41, x77, u64(0x0))
x83, _ := bits.add_u64(x42, x79, u64(fiat.u1(x82)))
x85, x86 := bits.add_u64(x25, x1, u64(0x0))
x87, _ := bits.add_u64(x26, x2, u64(fiat.u1(x86)))
x89, x90 := bits.add_u64(x29, x85, u64(0x0))
x91, _ := bits.add_u64(x30, x87, u64(fiat.u1(x90)))
x93, x94 := bits.add_u64(x35, x89, u64(0x0))
x95, _ := bits.add_u64(x36, x91, u64(fiat.u1(x94)))
x97, x98 := bits.add_u64(x43, x93, u64(0x0))
x99, _ := bits.add_u64(x44, x95, u64(fiat.u1(x98)))
x101, x102 := bits.add_u64(x9, x3, u64(0x0))
x103, _ := bits.add_u64(x10, x4, u64(fiat.u1(x102)))
x105, x106 := bits.add_u64(x31, x101, u64(0x0))
x107, _ := bits.add_u64(x32, x103, u64(fiat.u1(x106)))
x109, x110 := bits.add_u64(x37, x105, u64(0x0))
x111, _ := bits.add_u64(x38, x107, u64(fiat.u1(x110)))
x113, x114 := bits.add_u64(x45, x109, u64(0x0))
x115, _ := bits.add_u64(x46, x111, u64(fiat.u1(x114)))
x117, x118 := bits.add_u64(x11, x5, u64(0x0))
x119, _ := bits.add_u64(x12, x6, u64(fiat.u1(x118)))
x121, x122 := bits.add_u64(x15, x117, u64(0x0))
x123, _ := bits.add_u64(x16, x119, u64(fiat.u1(x122)))
x125, x126 := bits.add_u64(x39, x121, u64(0x0))
x127, _ := bits.add_u64(x40, x123, u64(fiat.u1(x126)))
x129, x130 := bits.add_u64(x47, x125, u64(0x0))
x131, _ := bits.add_u64(x48, x127, u64(fiat.u1(x130)))
x133, x134 := bits.add_u64(x67, x129, u64(0x0))
x135 := (u64(fiat.u1(x134)) + x131)
x136 := ((x133 >> 51) | ((x135 << 13) & 0xffffffffffffffff))
x137 := (x133 & 0x7ffffffffffff)
x138, x139 := bits.add_u64(x136, x113, u64(0x0))
x140 := (u64(fiat.u1(x139)) + x115)
x141 := ((x138 >> 51) | ((x140 << 13) & 0xffffffffffffffff))
x142 := (x138 & 0x7ffffffffffff)
x143, x144 := bits.add_u64(x141, x97, u64(0x0))
x145 := (u64(fiat.u1(x144)) + x99)
x146 := ((x143 >> 51) | ((x145 << 13) & 0xffffffffffffffff))
x147 := (x143 & 0x7ffffffffffff)
x148, x149 := bits.add_u64(x146, x81, u64(0x0))
x150 := (u64(fiat.u1(x149)) + x83)
x151 := ((x148 >> 51) | ((x150 << 13) & 0xffffffffffffffff))
x152 := (x148 & 0x7ffffffffffff)
x153 := (x151 * 0x13)
x154 := (x68 + x153)
x155 := (x154 >> 51)
x156 := (x154 & 0x7ffffffffffff)
x157 := (x155 + x137)
x158 := fiat.u1((x157 >> 51))
x159 := (x157 & 0x7ffffffffffff)
x160 := (u64(x158) + x142)
out1[0] = x156
out1[1] = x159
out1[2] = x160
out1[3] = x147
out1[4] = x152
}
fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x1 := (arg1[4] * 0x13)
x2 := (x1 * 0x2)
x3 := (arg1[4] * 0x2)
x4 := (arg1[3] * 0x13)
x5 := (x4 * 0x2)
x6 := (arg1[3] * 0x2)
x7 := (arg1[2] * 0x2)
x8 := (arg1[1] * 0x2)
x10, x9 := bits.mul_u64(arg1[4], x1)
x12, x11 := bits.mul_u64(arg1[3], x2)
x14, x13 := bits.mul_u64(arg1[3], x4)
x16, x15 := bits.mul_u64(arg1[2], x2)
x18, x17 := bits.mul_u64(arg1[2], x5)
x20, x19 := bits.mul_u64(arg1[2], arg1[2])
x22, x21 := bits.mul_u64(arg1[1], x2)
x24, x23 := bits.mul_u64(arg1[1], x6)
x26, x25 := bits.mul_u64(arg1[1], x7)
x28, x27 := bits.mul_u64(arg1[1], arg1[1])
x30, x29 := bits.mul_u64(arg1[0], x3)
x32, x31 := bits.mul_u64(arg1[0], x6)
x34, x33 := bits.mul_u64(arg1[0], x7)
x36, x35 := bits.mul_u64(arg1[0], x8)
x38, x37 := bits.mul_u64(arg1[0], arg1[0])
x39, x40 := bits.add_u64(x21, x17, u64(0x0))
x41, _ := bits.add_u64(x22, x18, u64(fiat.u1(x40)))
x43, x44 := bits.add_u64(x37, x39, u64(0x0))
x45, _ := bits.add_u64(x38, x41, u64(fiat.u1(x44)))
x47 := ((x43 >> 51) | ((x45 << 13) & 0xffffffffffffffff))
x48 := (x43 & 0x7ffffffffffff)
x49, x50 := bits.add_u64(x23, x19, u64(0x0))
x51, _ := bits.add_u64(x24, x20, u64(fiat.u1(x50)))
x53, x54 := bits.add_u64(x29, x49, u64(0x0))
x55, _ := bits.add_u64(x30, x51, u64(fiat.u1(x54)))
x57, x58 := bits.add_u64(x25, x9, u64(0x0))
x59, _ := bits.add_u64(x26, x10, u64(fiat.u1(x58)))
x61, x62 := bits.add_u64(x31, x57, u64(0x0))
x63, _ := bits.add_u64(x32, x59, u64(fiat.u1(x62)))
x65, x66 := bits.add_u64(x27, x11, u64(0x0))
x67, _ := bits.add_u64(x28, x12, u64(fiat.u1(x66)))
x69, x70 := bits.add_u64(x33, x65, u64(0x0))
x71, _ := bits.add_u64(x34, x67, u64(fiat.u1(x70)))
x73, x74 := bits.add_u64(x15, x13, u64(0x0))
x75, _ := bits.add_u64(x16, x14, u64(fiat.u1(x74)))
x77, x78 := bits.add_u64(x35, x73, u64(0x0))
x79, _ := bits.add_u64(x36, x75, u64(fiat.u1(x78)))
x81, x82 := bits.add_u64(x47, x77, u64(0x0))
x83 := (u64(fiat.u1(x82)) + x79)
x84 := ((x81 >> 51) | ((x83 << 13) & 0xffffffffffffffff))
x85 := (x81 & 0x7ffffffffffff)
x86, x87 := bits.add_u64(x84, x69, u64(0x0))
x88 := (u64(fiat.u1(x87)) + x71)
x89 := ((x86 >> 51) | ((x88 << 13) & 0xffffffffffffffff))
x90 := (x86 & 0x7ffffffffffff)
x91, x92 := bits.add_u64(x89, x61, u64(0x0))
x93 := (u64(fiat.u1(x92)) + x63)
x94 := ((x91 >> 51) | ((x93 << 13) & 0xffffffffffffffff))
x95 := (x91 & 0x7ffffffffffff)
x96, x97 := bits.add_u64(x94, x53, u64(0x0))
x98 := (u64(fiat.u1(x97)) + x55)
x99 := ((x96 >> 51) | ((x98 << 13) & 0xffffffffffffffff))
x100 := (x96 & 0x7ffffffffffff)
x101 := (x99 * 0x13)
x102 := (x48 + x101)
x103 := (x102 >> 51)
x104 := (x102 & 0x7ffffffffffff)
x105 := (x103 + x85)
x106 := fiat.u1((x105 >> 51))
x107 := (x105 & 0x7ffffffffffff)
x108 := (u64(x106) + x90)
out1[0] = x104
out1[1] = x107
out1[2] = x108
out1[3] = x95
out1[4] = x100
}
fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x1 := arg1[0]
x2 := ((x1 >> 51) + arg1[1])
x3 := ((x2 >> 51) + arg1[2])
x4 := ((x3 >> 51) + arg1[3])
x5 := ((x4 >> 51) + arg1[4])
x6 := ((x1 & 0x7ffffffffffff) + ((x5 >> 51) * 0x13))
x7 := (u64(fiat.u1((x6 >> 51))) + (x2 & 0x7ffffffffffff))
x8 := (x6 & 0x7ffffffffffff)
x9 := (x7 & 0x7ffffffffffff)
x10 := (u64(fiat.u1((x7 >> 51))) + (x3 & 0x7ffffffffffff))
x11 := (x4 & 0x7ffffffffffff)
x12 := (x5 & 0x7ffffffffffff)
out1[0] = x8
out1[1] = x9
out1[2] = x10
out1[3] = x11
out1[4] = x12
}
fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
x1 := (arg1[0] + arg2[0])
x2 := (arg1[1] + arg2[1])
x3 := (arg1[2] + arg2[2])
x4 := (arg1[3] + arg2[3])
x5 := (arg1[4] + arg2[4])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
x1 := ((0xfffffffffffda + arg1[0]) - arg2[0])
x2 := ((0xffffffffffffe + arg1[1]) - arg2[1])
x3 := ((0xffffffffffffe + arg1[2]) - arg2[2])
x4 := ((0xffffffffffffe + arg1[3]) - arg2[3])
x5 := ((0xffffffffffffe + arg1[4]) - arg2[4])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
x1 := (0xfffffffffffda - arg1[0])
x2 := (0xffffffffffffe - arg1[1])
x3 := (0xffffffffffffe - arg1[2])
x4 := (0xffffffffffffe - arg1[3])
x5 := (0xffffffffffffe - arg1[4])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3])
x5 := fiat.cmovznz_u64(fiat.u1(arg2), out1[4], arg1[4])
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_to_bytes :: proc "contextless" (out1: ^[32]byte, arg1: ^Tight_Field_Element) {
x1, x2 := _subborrowx_u51(0x0, arg1[0], 0x7ffffffffffed)
x3, x4 := _subborrowx_u51(x2, arg1[1], 0x7ffffffffffff)
x5, x6 := _subborrowx_u51(x4, arg1[2], 0x7ffffffffffff)
x7, x8 := _subborrowx_u51(x6, arg1[3], 0x7ffffffffffff)
x9, x10 := _subborrowx_u51(x8, arg1[4], 0x7ffffffffffff)
x11 := fiat.cmovznz_u64(x10, u64(0x0), 0xffffffffffffffff)
x12, x13 := _addcarryx_u51(0x0, x1, (x11 & 0x7ffffffffffed))
x14, x15 := _addcarryx_u51(x13, x3, (x11 & 0x7ffffffffffff))
x16, x17 := _addcarryx_u51(x15, x5, (x11 & 0x7ffffffffffff))
x18, x19 := _addcarryx_u51(x17, x7, (x11 & 0x7ffffffffffff))
x20, _ := _addcarryx_u51(x19, x9, (x11 & 0x7ffffffffffff))
x22 := (x20 << 4)
x23 := (x18 * u64(0x2))
x24 := (x16 << 6)
x25 := (x14 << 3)
x26 := (u8(x12) & 0xff)
x27 := (x12 >> 8)
x28 := (u8(x27) & 0xff)
x29 := (x27 >> 8)
x30 := (u8(x29) & 0xff)
x31 := (x29 >> 8)
x32 := (u8(x31) & 0xff)
x33 := (x31 >> 8)
x34 := (u8(x33) & 0xff)
x35 := (x33 >> 8)
x36 := (u8(x35) & 0xff)
x37 := u8((x35 >> 8))
x38 := (x25 + u64(x37))
x39 := (u8(x38) & 0xff)
x40 := (x38 >> 8)
x41 := (u8(x40) & 0xff)
x42 := (x40 >> 8)
x43 := (u8(x42) & 0xff)
x44 := (x42 >> 8)
x45 := (u8(x44) & 0xff)
x46 := (x44 >> 8)
x47 := (u8(x46) & 0xff)
x48 := (x46 >> 8)
x49 := (u8(x48) & 0xff)
x50 := u8((x48 >> 8))
x51 := (x24 + u64(x50))
x52 := (u8(x51) & 0xff)
x53 := (x51 >> 8)
x54 := (u8(x53) & 0xff)
x55 := (x53 >> 8)
x56 := (u8(x55) & 0xff)
x57 := (x55 >> 8)
x58 := (u8(x57) & 0xff)
x59 := (x57 >> 8)
x60 := (u8(x59) & 0xff)
x61 := (x59 >> 8)
x62 := (u8(x61) & 0xff)
x63 := (x61 >> 8)
x64 := (u8(x63) & 0xff)
x65 := fiat.u1((x63 >> 8))
x66 := (x23 + u64(x65))
x67 := (u8(x66) & 0xff)
x68 := (x66 >> 8)
x69 := (u8(x68) & 0xff)
x70 := (x68 >> 8)
x71 := (u8(x70) & 0xff)
x72 := (x70 >> 8)
x73 := (u8(x72) & 0xff)
x74 := (x72 >> 8)
x75 := (u8(x74) & 0xff)
x76 := (x74 >> 8)
x77 := (u8(x76) & 0xff)
x78 := u8((x76 >> 8))
x79 := (x22 + u64(x78))
x80 := (u8(x79) & 0xff)
x81 := (x79 >> 8)
x82 := (u8(x81) & 0xff)
x83 := (x81 >> 8)
x84 := (u8(x83) & 0xff)
x85 := (x83 >> 8)
x86 := (u8(x85) & 0xff)
x87 := (x85 >> 8)
x88 := (u8(x87) & 0xff)
x89 := (x87 >> 8)
x90 := (u8(x89) & 0xff)
x91 := u8((x89 >> 8))
out1[0] = x26
out1[1] = x28
out1[2] = x30
out1[3] = x32
out1[4] = x34
out1[5] = x36
out1[6] = x39
out1[7] = x41
out1[8] = x43
out1[9] = x45
out1[10] = x47
out1[11] = x49
out1[12] = x52
out1[13] = x54
out1[14] = x56
out1[15] = x58
out1[16] = x60
out1[17] = x62
out1[18] = x64
out1[19] = x67
out1[20] = x69
out1[21] = x71
out1[22] = x73
out1[23] = x75
out1[24] = x77
out1[25] = x80
out1[26] = x82
out1[27] = x84
out1[28] = x86
out1[29] = x88
out1[30] = x90
out1[31] = x91
}
_fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
x1 := (u64(arg1[31]) << 44)
x2 := (u64(arg1[30]) << 36)
x3 := (u64(arg1[29]) << 28)
x4 := (u64(arg1[28]) << 20)
x5 := (u64(arg1[27]) << 12)
x6 := (u64(arg1[26]) << 4)
x7 := (u64(arg1[25]) << 47)
x8 := (u64(arg1[24]) << 39)
x9 := (u64(arg1[23]) << 31)
x10 := (u64(arg1[22]) << 23)
x11 := (u64(arg1[21]) << 15)
x12 := (u64(arg1[20]) << 7)
x13 := (u64(arg1[19]) << 50)
x14 := (u64(arg1[18]) << 42)
x15 := (u64(arg1[17]) << 34)
x16 := (u64(arg1[16]) << 26)
x17 := (u64(arg1[15]) << 18)
x18 := (u64(arg1[14]) << 10)
x19 := (u64(arg1[13]) << 2)
x20 := (u64(arg1[12]) << 45)
x21 := (u64(arg1[11]) << 37)
x22 := (u64(arg1[10]) << 29)
x23 := (u64(arg1[9]) << 21)
x24 := (u64(arg1[8]) << 13)
x25 := (u64(arg1[7]) << 5)
x26 := (u64(arg1[6]) << 48)
x27 := (u64(arg1[5]) << 40)
x28 := (u64(arg1[4]) << 32)
x29 := (u64(arg1[3]) << 24)
x30 := (u64(arg1[2]) << 16)
x31 := (u64(arg1[1]) << 8)
x32 := arg1[0]
x33 := (x31 + u64(x32))
x34 := (x30 + x33)
x35 := (x29 + x34)
x36 := (x28 + x35)
x37 := (x27 + x36)
x38 := (x26 + x37)
x39 := (x38 & 0x7ffffffffffff)
x40 := u8((x38 >> 51))
x41 := (x25 + u64(x40))
x42 := (x24 + x41)
x43 := (x23 + x42)
x44 := (x22 + x43)
x45 := (x21 + x44)
x46 := (x20 + x45)
x47 := (x46 & 0x7ffffffffffff)
x48 := u8((x46 >> 51))
x49 := (x19 + u64(x48))
x50 := (x18 + x49)
x51 := (x17 + x50)
x52 := (x16 + x51)
x53 := (x15 + x52)
x54 := (x14 + x53)
x55 := (x13 + x54)
x56 := (x55 & 0x7ffffffffffff)
x57 := u8((x55 >> 51))
x58 := (x12 + u64(x57))
x59 := (x11 + x58)
x60 := (x10 + x59)
x61 := (x9 + x60)
x62 := (x8 + x61)
x63 := (x7 + x62)
x64 := (x63 & 0x7ffffffffffff)
x65 := u8((x63 >> 51))
x66 := (x6 + u64(x65))
x67 := (x5 + x66)
x68 := (x4 + x67)
x69 := (x3 + x68)
x70 := (x2 + x69)
x71 := (x1 + x70)
out1[0] = x39
out1[1] = x47
out1[2] = x56
out1[3] = x64
out1[4] = x71
}
fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
x5 := arg1[4]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_carry_scmul_121666 :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x2, x1 := bits.mul_u64(0x1db42, arg1[4])
x4, x3 := bits.mul_u64(0x1db42, arg1[3])
x6, x5 := bits.mul_u64(0x1db42, arg1[2])
x8, x7 := bits.mul_u64(0x1db42, arg1[1])
x10, x9 := bits.mul_u64(0x1db42, arg1[0])
x11 := ((x9 >> 51) | ((x10 << 13) & 0xffffffffffffffff))
x12 := (x9 & 0x7ffffffffffff)
x13, x14 := bits.add_u64(x11, x7, u64(0x0))
x15 := (u64(fiat.u1(x14)) + x8)
x16 := ((x13 >> 51) | ((x15 << 13) & 0xffffffffffffffff))
x17 := (x13 & 0x7ffffffffffff)
x18, x19 := bits.add_u64(x16, x5, u64(0x0))
x20 := (u64(fiat.u1(x19)) + x6)
x21 := ((x18 >> 51) | ((x20 << 13) & 0xffffffffffffffff))
x22 := (x18 & 0x7ffffffffffff)
x23, x24 := bits.add_u64(x21, x3, u64(0x0))
x25 := (u64(fiat.u1(x24)) + x4)
x26 := ((x23 >> 51) | ((x25 << 13) & 0xffffffffffffffff))
x27 := (x23 & 0x7ffffffffffff)
x28, x29 := bits.add_u64(x26, x1, u64(0x0))
x30 := (u64(fiat.u1(x29)) + x2)
x31 := ((x28 >> 51) | ((x30 << 13) & 0xffffffffffffffff))
x32 := (x28 & 0x7ffffffffffff)
x33 := (x31 * 0x13)
x34 := (x12 + x33)
x35 := fiat.u1((x34 >> 51))
x36 := (x34 & 0x7ffffffffffff)
x37 := (u64(x35) + x17)
x38 := fiat.u1((x37 >> 51))
x39 := (x37 & 0x7ffffffffffff)
x40 := (u64(x38) + x22)
out1[0] = x36
out1[1] = x39
out1[2] = x40
out1[3] = x27
out1[4] = x32
}
// The following routines were added by hand, and do not come from fiat-crypto.
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
out1[3] = 0
out1[4] = 0
}
fe_one :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 1
out1[1] = 0
out1[2] = 0
out1[3] = 0
out1[4] = 0
}
fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
x4 := arg1[3]
x5 := arg1[4]
out1[0] = x1
out1[1] = x2
out1[2] = x3
out1[3] = x4
out1[4] = x5
}
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) {
mask := -u64(arg1)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
x = (out1[3] ~ out2[3]) & mask
x4, y4 := out1[3] ~ x, out2[3] ~ x
x = (out1[4] ~ out2[4]) & mask
x5, y5 := out1[4] ~ x, out2[4] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
out1[3], out2[3] = x4, y4
out1[4], out2[4] = x5, y5
}
@@ -0,0 +1,66 @@
package field_poly1305
import "core:crypto/util"
import "core:mem"
fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element {
return transmute(^Loose_Field_Element)(arg1)
}
fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element {
return transmute(^Tight_Field_Element)(arg1)
}
fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) {
// fiat-crypto's deserialization routine effectively processes a
// single byte at a time, and wants 256-bits of input for a value
// that will be 128-bits or 129-bits.
//
// This is somewhat cumbersome to use, so at a minimum a wrapper
// makes implementing the actual MAC block processing considerably
// neater.
assert(len(arg1) == 16)
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
// While it may be unwise to do deserialization here on our
// own when fiat-crypto provides equivalent functionality,
// doing it this way provides a little under 3x performance
// improvement when optimization is enabled.
src_p := transmute(^[2]u64)(&arg1[0])
lo := src_p[0]
hi := src_p[1]
// This is inspired by poly1305-donna, though adjustments were
// made since a Tight_Field_Element's limbs are 44-bits, 43-bits,
// and 43-bits wide.
//
// Note: This could be transplated into fe_from_u64s, but that
// code is called once per MAC, and is non-criticial path.
hibit := u64(arg2) << 41 // arg2 << 128
out1[0] = lo & 0xfffffffffff
out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff
out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit
} else {
tmp: [32]byte
copy_slice(tmp[0:16], arg1[:])
tmp[16] = arg2
_fe_from_bytes(out1, &tmp)
if sanitize {
// This is used to deserialize `s` which is confidential.
mem.zero_explicit(&tmp, size_of(tmp))
}
}
}
fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) {
tmp: [32]byte
util.PUT_U64_LE(tmp[0:8], lo)
util.PUT_U64_LE(tmp[8:16], hi)
_fe_from_bytes(out1, &tmp)
// This routine is only used to deserialize `r` which is confidential.
mem.zero_explicit(&tmp, size_of(tmp))
}
@@ -0,0 +1,356 @@
// The BSD 1-Clause License (BSD-1-Clause)
//
// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package field_poly1305
// This file provides arithmetic on the field Z/(2^130 - 5) using
// unsaturated 64-bit integer arithmetic. It is derived primarily
// from the machine generate Golang output from the fiat-crypto project.
//
// While the base implementation is provably correct, this implementation
// makes no such claims as the port and optimizations were done by hand.
// At some point, it may be worth adding support to fiat-crypto for
// generating Odin output.
import fiat "core:crypto/_fiat"
import "core:math/bits"
Loose_Field_Element :: distinct [3]u64
Tight_Field_Element :: distinct [3]u64
_addcarryx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
x1 := ((u64(arg1) + arg2) + arg3)
x2 := (x1 & 0xfffffffffff)
x3 := fiat.u1((x1 >> 44))
out1 = x2
out2 = x3
return
}
_subborrowx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
x2 := fiat.i1((x1 >> 44))
x3 := (u64(x1) & 0xfffffffffff)
out1 = x3
out2 = (0x0 - fiat.u1(x2))
return
}
_addcarryx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
x1 := ((u64(arg1) + arg2) + arg3)
x2 := (x1 & 0x7ffffffffff)
x3 := fiat.u1((x1 >> 43))
out1 = x2
out2 = x3
return
}
_subborrowx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) {
x1 := ((i64(arg2) - i64(arg1)) - i64(arg3))
x2 := fiat.i1((x1 >> 43))
x3 := (u64(x1) & 0x7ffffffffff)
out1 = x3
out2 = (0x0 - fiat.u1(x2))
return
}
fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) {
x2, x1 := bits.mul_u64(arg1[2], (arg2[2] * 0x5))
x4, x3 := bits.mul_u64(arg1[2], (arg2[1] * 0xa))
x6, x5 := bits.mul_u64(arg1[1], (arg2[2] * 0xa))
x8, x7 := bits.mul_u64(arg1[2], arg2[0])
x10, x9 := bits.mul_u64(arg1[1], (arg2[1] * 0x2))
x12, x11 := bits.mul_u64(arg1[1], arg2[0])
x14, x13 := bits.mul_u64(arg1[0], arg2[2])
x16, x15 := bits.mul_u64(arg1[0], arg2[1])
x18, x17 := bits.mul_u64(arg1[0], arg2[0])
x19, x20 := bits.add_u64(x5, x3, u64(0x0))
x21, _ := bits.add_u64(x6, x4, u64(fiat.u1(x20)))
x23, x24 := bits.add_u64(x17, x19, u64(0x0))
x25, _ := bits.add_u64(x18, x21, u64(fiat.u1(x24)))
x27 := ((x23 >> 44) | ((x25 << 20) & 0xffffffffffffffff))
x28 := (x23 & 0xfffffffffff)
x29, x30 := bits.add_u64(x9, x7, u64(0x0))
x31, _ := bits.add_u64(x10, x8, u64(fiat.u1(x30)))
x33, x34 := bits.add_u64(x13, x29, u64(0x0))
x35, _ := bits.add_u64(x14, x31, u64(fiat.u1(x34)))
x37, x38 := bits.add_u64(x11, x1, u64(0x0))
x39, _ := bits.add_u64(x12, x2, u64(fiat.u1(x38)))
x41, x42 := bits.add_u64(x15, x37, u64(0x0))
x43, _ := bits.add_u64(x16, x39, u64(fiat.u1(x42)))
x45, x46 := bits.add_u64(x27, x41, u64(0x0))
x47 := (u64(fiat.u1(x46)) + x43)
x48 := ((x45 >> 43) | ((x47 << 21) & 0xffffffffffffffff))
x49 := (x45 & 0x7ffffffffff)
x50, x51 := bits.add_u64(x48, x33, u64(0x0))
x52 := (u64(fiat.u1(x51)) + x35)
x53 := ((x50 >> 43) | ((x52 << 21) & 0xffffffffffffffff))
x54 := (x50 & 0x7ffffffffff)
x55 := (x53 * 0x5)
x56 := (x28 + x55)
x57 := (x56 >> 44)
x58 := (x56 & 0xfffffffffff)
x59 := (x57 + x49)
x60 := fiat.u1((x59 >> 43))
x61 := (x59 & 0x7ffffffffff)
x62 := (u64(x60) + x54)
out1[0] = x58
out1[1] = x61
out1[2] = x62
}
fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x1 := (arg1[2] * 0x5)
x2 := (x1 * 0x2)
x3 := (arg1[2] * 0x2)
x4 := (arg1[1] * 0x2)
x6, x5 := bits.mul_u64(arg1[2], x1)
x8, x7 := bits.mul_u64(arg1[1], (x2 * 0x2))
x10, x9 := bits.mul_u64(arg1[1], (arg1[1] * 0x2))
x12, x11 := bits.mul_u64(arg1[0], x3)
x14, x13 := bits.mul_u64(arg1[0], x4)
x16, x15 := bits.mul_u64(arg1[0], arg1[0])
x17, x18 := bits.add_u64(x15, x7, u64(0x0))
x19, _ := bits.add_u64(x16, x8, u64(fiat.u1(x18)))
x21 := ((x17 >> 44) | ((x19 << 20) & 0xffffffffffffffff))
x22 := (x17 & 0xfffffffffff)
x23, x24 := bits.add_u64(x11, x9, u64(0x0))
x25, _ := bits.add_u64(x12, x10, u64(fiat.u1(x24)))
x27, x28 := bits.add_u64(x13, x5, u64(0x0))
x29, _ := bits.add_u64(x14, x6, u64(fiat.u1(x28)))
x31, x32 := bits.add_u64(x21, x27, u64(0x0))
x33 := (u64(fiat.u1(x32)) + x29)
x34 := ((x31 >> 43) | ((x33 << 21) & 0xffffffffffffffff))
x35 := (x31 & 0x7ffffffffff)
x36, x37 := bits.add_u64(x34, x23, u64(0x0))
x38 := (u64(fiat.u1(x37)) + x25)
x39 := ((x36 >> 43) | ((x38 << 21) & 0xffffffffffffffff))
x40 := (x36 & 0x7ffffffffff)
x41 := (x39 * 0x5)
x42 := (x22 + x41)
x43 := (x42 >> 44)
x44 := (x42 & 0xfffffffffff)
x45 := (x43 + x35)
x46 := fiat.u1((x45 >> 43))
x47 := (x45 & 0x7ffffffffff)
x48 := (u64(x46) + x40)
out1[0] = x44
out1[1] = x47
out1[2] = x48
}
fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) {
x1 := arg1[0]
x2 := ((x1 >> 44) + arg1[1])
x3 := ((x2 >> 43) + arg1[2])
x4 := ((x1 & 0xfffffffffff) + ((x3 >> 43) * 0x5))
x5 := (u64(fiat.u1((x4 >> 44))) + (x2 & 0x7ffffffffff))
x6 := (x4 & 0xfffffffffff)
x7 := (x5 & 0x7ffffffffff)
x8 := (u64(fiat.u1((x5 >> 43))) + (x3 & 0x7ffffffffff))
out1[0] = x6
out1[1] = x7
out1[2] = x8
}
fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
x1 := (arg1[0] + arg2[0])
x2 := (arg1[1] + arg2[1])
x3 := (arg1[2] + arg2[2])
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) {
x1 := ((0x1ffffffffff6 + arg1[0]) - arg2[0])
x2 := ((0xffffffffffe + arg1[1]) - arg2[1])
x3 := ((0xffffffffffe + arg1[2]) - arg2[2])
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
x1 := (0x1ffffffffff6 - arg1[0])
x2 := (0xffffffffffe - arg1[1])
x3 := (0xffffffffffe - arg1[2])
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) {
x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0])
x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1])
x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2])
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
fe_to_bytes :: proc "contextless" (out1: ^[32]byte, arg1: ^Tight_Field_Element) {
x1, x2 := _subborrowx_u44(0x0, arg1[0], 0xffffffffffb)
x3, x4 := _subborrowx_u43(x2, arg1[1], 0x7ffffffffff)
x5, x6 := _subborrowx_u43(x4, arg1[2], 0x7ffffffffff)
x7 := fiat.cmovznz_u64(x6, u64(0x0), 0xffffffffffffffff)
x8, x9 := _addcarryx_u44(0x0, x1, (x7 & 0xffffffffffb))
x10, x11 := _addcarryx_u43(x9, x3, (x7 & 0x7ffffffffff))
x12, _ := _addcarryx_u43(x11, x5, (x7 & 0x7ffffffffff))
x14 := (x12 << 7)
x15 := (x10 << 4)
x16 := (u8(x8) & 0xff)
x17 := (x8 >> 8)
x18 := (u8(x17) & 0xff)
x19 := (x17 >> 8)
x20 := (u8(x19) & 0xff)
x21 := (x19 >> 8)
x22 := (u8(x21) & 0xff)
x23 := (x21 >> 8)
x24 := (u8(x23) & 0xff)
x25 := u8((x23 >> 8))
x26 := (x15 + u64(x25))
x27 := (u8(x26) & 0xff)
x28 := (x26 >> 8)
x29 := (u8(x28) & 0xff)
x30 := (x28 >> 8)
x31 := (u8(x30) & 0xff)
x32 := (x30 >> 8)
x33 := (u8(x32) & 0xff)
x34 := (x32 >> 8)
x35 := (u8(x34) & 0xff)
x36 := u8((x34 >> 8))
x37 := (x14 + u64(x36))
x38 := (u8(x37) & 0xff)
x39 := (x37 >> 8)
x40 := (u8(x39) & 0xff)
x41 := (x39 >> 8)
x42 := (u8(x41) & 0xff)
x43 := (x41 >> 8)
x44 := (u8(x43) & 0xff)
x45 := (x43 >> 8)
x46 := (u8(x45) & 0xff)
x47 := (x45 >> 8)
x48 := (u8(x47) & 0xff)
x49 := u8((x47 >> 8))
out1[0] = x16
out1[1] = x18
out1[2] = x20
out1[3] = x22
out1[4] = x24
out1[5] = x27
out1[6] = x29
out1[7] = x31
out1[8] = x33
out1[9] = x35
out1[10] = x38
out1[11] = x40
out1[12] = x42
out1[13] = x44
out1[14] = x46
out1[15] = x48
out1[16] = x49
}
_fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) {
x1 := (u64(arg1[16]) << 41)
x2 := (u64(arg1[15]) << 33)
x3 := (u64(arg1[14]) << 25)
x4 := (u64(arg1[13]) << 17)
x5 := (u64(arg1[12]) << 9)
x6 := (u64(arg1[11]) * u64(0x2))
x7 := (u64(arg1[10]) << 36)
x8 := (u64(arg1[9]) << 28)
x9 := (u64(arg1[8]) << 20)
x10 := (u64(arg1[7]) << 12)
x11 := (u64(arg1[6]) << 4)
x12 := (u64(arg1[5]) << 40)
x13 := (u64(arg1[4]) << 32)
x14 := (u64(arg1[3]) << 24)
x15 := (u64(arg1[2]) << 16)
x16 := (u64(arg1[1]) << 8)
x17 := arg1[0]
x18 := (x16 + u64(x17))
x19 := (x15 + x18)
x20 := (x14 + x19)
x21 := (x13 + x20)
x22 := (x12 + x21)
x23 := (x22 & 0xfffffffffff)
x24 := u8((x22 >> 44))
x25 := (x11 + u64(x24))
x26 := (x10 + x25)
x27 := (x9 + x26)
x28 := (x8 + x27)
x29 := (x7 + x28)
x30 := (x29 & 0x7ffffffffff)
x31 := fiat.u1((x29 >> 43))
x32 := (x6 + u64(x31))
x33 := (x5 + x32)
x34 := (x4 + x33)
x35 := (x3 + x34)
x36 := (x2 + x35)
x37 := (x1 + x36)
out1[0] = x23
out1[1] = x30
out1[2] = x37
}
fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
// The following routines were added by hand, and do not come from fiat-crypto.
fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) {
out1[0] = 0
out1[1] = 0
out1[2] = 0
}
fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) {
x1 := arg1[0]
x2 := arg1[1]
x3 := arg1[2]
out1[0] = x1
out1[1] = x2
out1[2] = x3
}
fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) {
mask := -u64(arg1)
x := (out1[0] ~ out2[0]) & mask
x1, y1 := out1[0] ~ x, out2[0] ~ x
x = (out1[1] ~ out2[1]) & mask
x2, y2 := out1[1] ~ x, out2[1] ~ x
x = (out1[2] ~ out2[2]) & mask
x3, y3 := out1[2] ~ x, out2[2] ~ x
out1[0], out2[0] = x1, y1
out1[1], out2[1] = x2, y2
out1[2], out2[2] = x3, y3
}
+169
View File
@@ -0,0 +1,169 @@
package _sha3
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the Keccak hashing algorithm, standardized as SHA3 in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>
To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding.
*/
import "../util"
ROUNDS :: 24
Sha3_Context :: struct {
st: struct #raw_union {
b: [200]u8,
q: [25]u64,
},
pt: int,
rsiz: int,
mdlen: int,
is_keccak: bool,
}
keccakf :: proc "contextless" (st: ^[25]u64) {
keccakf_rndc := [?]u64 {
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
}
keccakf_rotc := [?]i32 {
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
}
keccakf_piln := [?]i32 {
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
}
i, j, r: i32 = ---, ---, ---
t: u64 = ---
bc: [5]u64 = ---
when ODIN_ENDIAN != .Little {
v: uintptr = ---
for i = 0; i < 25; i += 1 {
v := uintptr(&st[i])
st[i] = u64((^u8)(v + 0)^ << 0) | u64((^u8)(v + 1)^ << 8) |
u64((^u8)(v + 2)^ << 16) | u64((^u8)(v + 3)^ << 24) |
u64((^u8)(v + 4)^ << 32) | u64((^u8)(v + 5)^ << 40) |
u64((^u8)(v + 6)^ << 48) | u64((^u8)(v + 7)^ << 56)
}
}
for r = 0; r < ROUNDS; r += 1 {
// theta
for i = 0; i < 5; i += 1 {
bc[i] = st[i] ~ st[i + 5] ~ st[i + 10] ~ st[i + 15] ~ st[i + 20]
}
for i = 0; i < 5; i += 1 {
t = bc[(i + 4) % 5] ~ util.ROTL64(bc[(i + 1) % 5], 1)
for j = 0; j < 25; j += 5 {
st[j + i] ~= t
}
}
// rho pi
t = st[1]
for i = 0; i < 24; i += 1 {
j = keccakf_piln[i]
bc[0] = st[j]
st[j] = util.ROTL64(t, u64(keccakf_rotc[i]))
t = bc[0]
}
// chi
for j = 0; j < 25; j += 5 {
for i = 0; i < 5; i += 1 {
bc[i] = st[j + i]
}
for i = 0; i < 5; i += 1 {
st[j + i] ~= ~bc[(i + 1) % 5] & bc[(i + 2) % 5]
}
}
st[0] ~= keccakf_rndc[r]
}
when ODIN_ENDIAN != .Little {
for i = 0; i < 25; i += 1 {
v = uintptr(&st[i])
t = st[i]
(^u8)(v + 0)^ = (t >> 0) & 0xff
(^u8)(v + 1)^ = (t >> 8) & 0xff
(^u8)(v + 2)^ = (t >> 16) & 0xff
(^u8)(v + 3)^ = (t >> 24) & 0xff
(^u8)(v + 4)^ = (t >> 32) & 0xff
(^u8)(v + 5)^ = (t >> 40) & 0xff
(^u8)(v + 6)^ = (t >> 48) & 0xff
(^u8)(v + 7)^ = (t >> 56) & 0xff
}
}
}
init :: proc "contextless" (c: ^Sha3_Context) {
for i := 0; i < 25; i += 1 {
c.st.q[i] = 0
}
c.rsiz = 200 - 2 * c.mdlen
}
update :: proc "contextless" (c: ^Sha3_Context, data: []byte) {
j := c.pt
for i := 0; i < len(data); i += 1 {
c.st.b[j] ~= data[i]
j += 1
if j >= c.rsiz {
keccakf(&c.st.q)
j = 0
}
}
c.pt = j
}
final :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
if c.is_keccak {
c.st.b[c.pt] ~= 0x01
} else {
c.st.b[c.pt] ~= 0x06
}
c.st.b[c.rsiz - 1] ~= 0x80
keccakf(&c.st.q)
for i := 0; i < c.mdlen; i += 1 {
hash[i] = c.st.b[i]
}
}
shake_xof :: proc "contextless" (c: ^Sha3_Context) {
c.st.b[c.pt] ~= 0x1F
c.st.b[c.rsiz - 1] ~= 0x80
keccakf(&c.st.q)
c.pt = 0
}
shake_out :: proc "contextless" (c: ^Sha3_Context, hash: []byte) {
j := c.pt
for i := 0; i < len(hash); i += 1 {
if j >= c.rsiz {
keccakf(&c.st.q)
j = 0
}
hash[i] = c.st.b[j]
j += 1
}
c.pt = j
}
+410
View File
@@ -0,0 +1,410 @@
package _tiger
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the Tiger hashing algorithm, as defined in <https://www.cs.technion.ac.il/~biham/Reports/Tiger/>
*/
import "../util"
T1 := [?]u64 {
0x02aab17cf7e90c5e, 0xac424b03e243a8ec, 0x72cd5be30dd5fcd3, 0x6d019b93f6f97f3a,
0xcd9978ffd21f9193, 0x7573a1c9708029e2, 0xb164326b922a83c3, 0x46883eee04915870,
0xeaace3057103ece6, 0xc54169b808a3535c, 0x4ce754918ddec47c, 0x0aa2f4dfdc0df40c,
0x10b76f18a74dbefa, 0xc6ccb6235ad1ab6a, 0x13726121572fe2ff, 0x1a488c6f199d921e,
0x4bc9f9f4da0007ca, 0x26f5e6f6e85241c7, 0x859079dbea5947b6, 0x4f1885c5c99e8c92,
0xd78e761ea96f864b, 0x8e36428c52b5c17d, 0x69cf6827373063c1, 0xb607c93d9bb4c56e,
0x7d820e760e76b5ea, 0x645c9cc6f07fdc42, 0xbf38a078243342e0, 0x5f6b343c9d2e7d04,
0xf2c28aeb600b0ec6, 0x6c0ed85f7254bcac, 0x71592281a4db4fe5, 0x1967fa69ce0fed9f,
0xfd5293f8b96545db, 0xc879e9d7f2a7600b, 0x860248920193194e, 0xa4f9533b2d9cc0b3,
0x9053836c15957613, 0xdb6dcf8afc357bf1, 0x18beea7a7a370f57, 0x037117ca50b99066,
0x6ab30a9774424a35, 0xf4e92f02e325249b, 0x7739db07061ccae1, 0xd8f3b49ceca42a05,
0xbd56be3f51382f73, 0x45faed5843b0bb28, 0x1c813d5c11bf1f83, 0x8af0e4b6d75fa169,
0x33ee18a487ad9999, 0x3c26e8eab1c94410, 0xb510102bc0a822f9, 0x141eef310ce6123b,
0xfc65b90059ddb154, 0xe0158640c5e0e607, 0x884e079826c3a3cf, 0x930d0d9523c535fd,
0x35638d754e9a2b00, 0x4085fccf40469dd5, 0xc4b17ad28be23a4c, 0xcab2f0fc6a3e6a2e,
0x2860971a6b943fcd, 0x3dde6ee212e30446, 0x6222f32ae01765ae, 0x5d550bb5478308fe,
0xa9efa98da0eda22a, 0xc351a71686c40da7, 0x1105586d9c867c84, 0xdcffee85fda22853,
0xccfbd0262c5eef76, 0xbaf294cb8990d201, 0xe69464f52afad975, 0x94b013afdf133e14,
0x06a7d1a32823c958, 0x6f95fe5130f61119, 0xd92ab34e462c06c0, 0xed7bde33887c71d2,
0x79746d6e6518393e, 0x5ba419385d713329, 0x7c1ba6b948a97564, 0x31987c197bfdac67,
0xde6c23c44b053d02, 0x581c49fed002d64d, 0xdd474d6338261571, 0xaa4546c3e473d062,
0x928fce349455f860, 0x48161bbacaab94d9, 0x63912430770e6f68, 0x6ec8a5e602c6641c,
0x87282515337ddd2b, 0x2cda6b42034b701b, 0xb03d37c181cb096d, 0xe108438266c71c6f,
0x2b3180c7eb51b255, 0xdf92b82f96c08bbc, 0x5c68c8c0a632f3ba, 0x5504cc861c3d0556,
0xabbfa4e55fb26b8f, 0x41848b0ab3baceb4, 0xb334a273aa445d32, 0xbca696f0a85ad881,
0x24f6ec65b528d56c, 0x0ce1512e90f4524a, 0x4e9dd79d5506d35a, 0x258905fac6ce9779,
0x2019295b3e109b33, 0xf8a9478b73a054cc, 0x2924f2f934417eb0, 0x3993357d536d1bc4,
0x38a81ac21db6ff8b, 0x47c4fbf17d6016bf, 0x1e0faadd7667e3f5, 0x7abcff62938beb96,
0xa78dad948fc179c9, 0x8f1f98b72911e50d, 0x61e48eae27121a91, 0x4d62f7ad31859808,
0xeceba345ef5ceaeb, 0xf5ceb25ebc9684ce, 0xf633e20cb7f76221, 0xa32cdf06ab8293e4,
0x985a202ca5ee2ca4, 0xcf0b8447cc8a8fb1, 0x9f765244979859a3, 0xa8d516b1a1240017,
0x0bd7ba3ebb5dc726, 0xe54bca55b86adb39, 0x1d7a3afd6c478063, 0x519ec608e7669edd,
0x0e5715a2d149aa23, 0x177d4571848ff194, 0xeeb55f3241014c22, 0x0f5e5ca13a6e2ec2,
0x8029927b75f5c361, 0xad139fabc3d6e436, 0x0d5df1a94ccf402f, 0x3e8bd948bea5dfc8,
0xa5a0d357bd3ff77e, 0xa2d12e251f74f645, 0x66fd9e525e81a082, 0x2e0c90ce7f687a49,
0xc2e8bcbeba973bc5, 0x000001bce509745f, 0x423777bbe6dab3d6, 0xd1661c7eaef06eb5,
0xa1781f354daacfd8, 0x2d11284a2b16affc, 0xf1fc4f67fa891d1f, 0x73ecc25dcb920ada,
0xae610c22c2a12651, 0x96e0a810d356b78a, 0x5a9a381f2fe7870f, 0xd5ad62ede94e5530,
0xd225e5e8368d1427, 0x65977b70c7af4631, 0x99f889b2de39d74f, 0x233f30bf54e1d143,
0x9a9675d3d9a63c97, 0x5470554ff334f9a8, 0x166acb744a4f5688, 0x70c74caab2e4aead,
0xf0d091646f294d12, 0x57b82a89684031d1, 0xefd95a5a61be0b6b, 0x2fbd12e969f2f29a,
0x9bd37013feff9fe8, 0x3f9b0404d6085a06, 0x4940c1f3166cfe15, 0x09542c4dcdf3defb,
0xb4c5218385cd5ce3, 0xc935b7dc4462a641, 0x3417f8a68ed3b63f, 0xb80959295b215b40,
0xf99cdaef3b8c8572, 0x018c0614f8fcb95d, 0x1b14accd1a3acdf3, 0x84d471f200bb732d,
0xc1a3110e95e8da16, 0x430a7220bf1a82b8, 0xb77e090d39df210e, 0x5ef4bd9f3cd05e9d,
0x9d4ff6da7e57a444, 0xda1d60e183d4a5f8, 0xb287c38417998e47, 0xfe3edc121bb31886,
0xc7fe3ccc980ccbef, 0xe46fb590189bfd03, 0x3732fd469a4c57dc, 0x7ef700a07cf1ad65,
0x59c64468a31d8859, 0x762fb0b4d45b61f6, 0x155baed099047718, 0x68755e4c3d50baa6,
0xe9214e7f22d8b4df, 0x2addbf532eac95f4, 0x32ae3909b4bd0109, 0x834df537b08e3450,
0xfa209da84220728d, 0x9e691d9b9efe23f7, 0x0446d288c4ae8d7f, 0x7b4cc524e169785b,
0x21d87f0135ca1385, 0xcebb400f137b8aa5, 0x272e2b66580796be, 0x3612264125c2b0de,
0x057702bdad1efbb2, 0xd4babb8eacf84be9, 0x91583139641bc67b, 0x8bdc2de08036e024,
0x603c8156f49f68ed, 0xf7d236f7dbef5111, 0x9727c4598ad21e80, 0xa08a0896670a5fd7,
0xcb4a8f4309eba9cb, 0x81af564b0f7036a1, 0xc0b99aa778199abd, 0x959f1ec83fc8e952,
0x8c505077794a81b9, 0x3acaaf8f056338f0, 0x07b43f50627a6778, 0x4a44ab49f5eccc77,
0x3bc3d6e4b679ee98, 0x9cc0d4d1cf14108c, 0x4406c00b206bc8a0, 0x82a18854c8d72d89,
0x67e366b35c3c432c, 0xb923dd61102b37f2, 0x56ab2779d884271d, 0xbe83e1b0ff1525af,
0xfb7c65d4217e49a9, 0x6bdbe0e76d48e7d4, 0x08df828745d9179e, 0x22ea6a9add53bd34,
0xe36e141c5622200a, 0x7f805d1b8cb750ee, 0xafe5c7a59f58e837, 0xe27f996a4fb1c23c,
0xd3867dfb0775f0d0, 0xd0e673de6e88891a, 0x123aeb9eafb86c25, 0x30f1d5d5c145b895,
0xbb434a2dee7269e7, 0x78cb67ecf931fa38, 0xf33b0372323bbf9c, 0x52d66336fb279c74,
0x505f33ac0afb4eaa, 0xe8a5cd99a2cce187, 0x534974801e2d30bb, 0x8d2d5711d5876d90,
0x1f1a412891bc038e, 0xd6e2e71d82e56648, 0x74036c3a497732b7, 0x89b67ed96361f5ab,
0xffed95d8f1ea02a2, 0xe72b3bd61464d43d, 0xa6300f170bdc4820, 0xebc18760ed78a77a,
}
T2 := [?]u64 {
0xe6a6be5a05a12138, 0xb5a122a5b4f87c98, 0x563c6089140b6990, 0x4c46cb2e391f5dd5,
0xd932addbc9b79434, 0x08ea70e42015aff5, 0xd765a6673e478cf1, 0xc4fb757eab278d99,
0xdf11c6862d6e0692, 0xddeb84f10d7f3b16, 0x6f2ef604a665ea04, 0x4a8e0f0ff0e0dfb3,
0xa5edeef83dbcba51, 0xfc4f0a2a0ea4371e, 0xe83e1da85cb38429, 0xdc8ff882ba1b1ce2,
0xcd45505e8353e80d, 0x18d19a00d4db0717, 0x34a0cfeda5f38101, 0x0be77e518887caf2,
0x1e341438b3c45136, 0xe05797f49089ccf9, 0xffd23f9df2591d14, 0x543dda228595c5cd,
0x661f81fd99052a33, 0x8736e641db0f7b76, 0x15227725418e5307, 0xe25f7f46162eb2fa,
0x48a8b2126c13d9fe, 0xafdc541792e76eea, 0x03d912bfc6d1898f, 0x31b1aafa1b83f51b,
0xf1ac2796e42ab7d9, 0x40a3a7d7fcd2ebac, 0x1056136d0afbbcc5, 0x7889e1dd9a6d0c85,
0xd33525782a7974aa, 0xa7e25d09078ac09b, 0xbd4138b3eac6edd0, 0x920abfbe71eb9e70,
0xa2a5d0f54fc2625c, 0xc054e36b0b1290a3, 0xf6dd59ff62fe932b, 0x3537354511a8ac7d,
0xca845e9172fadcd4, 0x84f82b60329d20dc, 0x79c62ce1cd672f18, 0x8b09a2add124642c,
0xd0c1e96a19d9e726, 0x5a786a9b4ba9500c, 0x0e020336634c43f3, 0xc17b474aeb66d822,
0x6a731ae3ec9baac2, 0x8226667ae0840258, 0x67d4567691caeca5, 0x1d94155c4875adb5,
0x6d00fd985b813fdf, 0x51286efcb774cd06, 0x5e8834471fa744af, 0xf72ca0aee761ae2e,
0xbe40e4cdaee8e09a, 0xe9970bbb5118f665, 0x726e4beb33df1964, 0x703b000729199762,
0x4631d816f5ef30a7, 0xb880b5b51504a6be, 0x641793c37ed84b6c, 0x7b21ed77f6e97d96,
0x776306312ef96b73, 0xae528948e86ff3f4, 0x53dbd7f286a3f8f8, 0x16cadce74cfc1063,
0x005c19bdfa52c6dd, 0x68868f5d64d46ad3, 0x3a9d512ccf1e186a, 0x367e62c2385660ae,
0xe359e7ea77dcb1d7, 0x526c0773749abe6e, 0x735ae5f9d09f734b, 0x493fc7cc8a558ba8,
0xb0b9c1533041ab45, 0x321958ba470a59bd, 0x852db00b5f46c393, 0x91209b2bd336b0e5,
0x6e604f7d659ef19f, 0xb99a8ae2782ccb24, 0xccf52ab6c814c4c7, 0x4727d9afbe11727b,
0x7e950d0c0121b34d, 0x756f435670ad471f, 0xf5add442615a6849, 0x4e87e09980b9957a,
0x2acfa1df50aee355, 0xd898263afd2fd556, 0xc8f4924dd80c8fd6, 0xcf99ca3d754a173a,
0xfe477bacaf91bf3c, 0xed5371f6d690c12d, 0x831a5c285e687094, 0xc5d3c90a3708a0a4,
0x0f7f903717d06580, 0x19f9bb13b8fdf27f, 0xb1bd6f1b4d502843, 0x1c761ba38fff4012,
0x0d1530c4e2e21f3b, 0x8943ce69a7372c8a, 0xe5184e11feb5ce66, 0x618bdb80bd736621,
0x7d29bad68b574d0b, 0x81bb613e25e6fe5b, 0x071c9c10bc07913f, 0xc7beeb7909ac2d97,
0xc3e58d353bc5d757, 0xeb017892f38f61e8, 0xd4effb9c9b1cc21a, 0x99727d26f494f7ab,
0xa3e063a2956b3e03, 0x9d4a8b9a4aa09c30, 0x3f6ab7d500090fb4, 0x9cc0f2a057268ac0,
0x3dee9d2dedbf42d1, 0x330f49c87960a972, 0xc6b2720287421b41, 0x0ac59ec07c00369c,
0xef4eac49cb353425, 0xf450244eef0129d8, 0x8acc46e5caf4deb6, 0x2ffeab63989263f7,
0x8f7cb9fe5d7a4578, 0x5bd8f7644e634635, 0x427a7315bf2dc900, 0x17d0c4aa2125261c,
0x3992486c93518e50, 0xb4cbfee0a2d7d4c3, 0x7c75d6202c5ddd8d, 0xdbc295d8e35b6c61,
0x60b369d302032b19, 0xce42685fdce44132, 0x06f3ddb9ddf65610, 0x8ea4d21db5e148f0,
0x20b0fce62fcd496f, 0x2c1b912358b0ee31, 0xb28317b818f5a308, 0xa89c1e189ca6d2cf,
0x0c6b18576aaadbc8, 0xb65deaa91299fae3, 0xfb2b794b7f1027e7, 0x04e4317f443b5beb,
0x4b852d325939d0a6, 0xd5ae6beefb207ffc, 0x309682b281c7d374, 0xbae309a194c3b475,
0x8cc3f97b13b49f05, 0x98a9422ff8293967, 0x244b16b01076ff7c, 0xf8bf571c663d67ee,
0x1f0d6758eee30da1, 0xc9b611d97adeb9b7, 0xb7afd5887b6c57a2, 0x6290ae846b984fe1,
0x94df4cdeacc1a5fd, 0x058a5bd1c5483aff, 0x63166cc142ba3c37, 0x8db8526eb2f76f40,
0xe10880036f0d6d4e, 0x9e0523c9971d311d, 0x45ec2824cc7cd691, 0x575b8359e62382c9,
0xfa9e400dc4889995, 0xd1823ecb45721568, 0xdafd983b8206082f, 0xaa7d29082386a8cb,
0x269fcd4403b87588, 0x1b91f5f728bdd1e0, 0xe4669f39040201f6, 0x7a1d7c218cf04ade,
0x65623c29d79ce5ce, 0x2368449096c00bb1, 0xab9bf1879da503ba, 0xbc23ecb1a458058e,
0x9a58df01bb401ecc, 0xa070e868a85f143d, 0x4ff188307df2239e, 0x14d565b41a641183,
0xee13337452701602, 0x950e3dcf3f285e09, 0x59930254b9c80953, 0x3bf299408930da6d,
0xa955943f53691387, 0xa15edecaa9cb8784, 0x29142127352be9a0, 0x76f0371fff4e7afb,
0x0239f450274f2228, 0xbb073af01d5e868b, 0xbfc80571c10e96c1, 0xd267088568222e23,
0x9671a3d48e80b5b0, 0x55b5d38ae193bb81, 0x693ae2d0a18b04b8, 0x5c48b4ecadd5335f,
0xfd743b194916a1ca, 0x2577018134be98c4, 0xe77987e83c54a4ad, 0x28e11014da33e1b9,
0x270cc59e226aa213, 0x71495f756d1a5f60, 0x9be853fb60afef77, 0xadc786a7f7443dbf,
0x0904456173b29a82, 0x58bc7a66c232bd5e, 0xf306558c673ac8b2, 0x41f639c6b6c9772a,
0x216defe99fda35da, 0x11640cc71c7be615, 0x93c43694565c5527, 0xea038e6246777839,
0xf9abf3ce5a3e2469, 0x741e768d0fd312d2, 0x0144b883ced652c6, 0xc20b5a5ba33f8552,
0x1ae69633c3435a9d, 0x97a28ca4088cfdec, 0x8824a43c1e96f420, 0x37612fa66eeea746,
0x6b4cb165f9cf0e5a, 0x43aa1c06a0abfb4a, 0x7f4dc26ff162796b, 0x6cbacc8e54ed9b0f,
0xa6b7ffefd2bb253e, 0x2e25bc95b0a29d4f, 0x86d6a58bdef1388c, 0xded74ac576b6f054,
0x8030bdbc2b45805d, 0x3c81af70e94d9289, 0x3eff6dda9e3100db, 0xb38dc39fdfcc8847,
0x123885528d17b87e, 0xf2da0ed240b1b642, 0x44cefadcd54bf9a9, 0x1312200e433c7ee6,
0x9ffcc84f3a78c748, 0xf0cd1f72248576bb, 0xec6974053638cfe4, 0x2ba7b67c0cec4e4c,
0xac2f4df3e5ce32ed, 0xcb33d14326ea4c11, 0xa4e9044cc77e58bc, 0x5f513293d934fcef,
0x5dc9645506e55444, 0x50de418f317de40a, 0x388cb31a69dde259, 0x2db4a83455820a86,
0x9010a91e84711ae9, 0x4df7f0b7b1498371, 0xd62a2eabc0977179, 0x22fac097aa8d5c0e,
}
T3 := [?]u64 {
0xf49fcc2ff1daf39b, 0x487fd5c66ff29281, 0xe8a30667fcdca83f, 0x2c9b4be3d2fcce63,
0xda3ff74b93fbbbc2, 0x2fa165d2fe70ba66, 0xa103e279970e93d4, 0xbecdec77b0e45e71,
0xcfb41e723985e497, 0xb70aaa025ef75017, 0xd42309f03840b8e0, 0x8efc1ad035898579,
0x96c6920be2b2abc5, 0x66af4163375a9172, 0x2174abdcca7127fb, 0xb33ccea64a72ff41,
0xf04a4933083066a5, 0x8d970acdd7289af5, 0x8f96e8e031c8c25e, 0xf3fec02276875d47,
0xec7bf310056190dd, 0xf5adb0aebb0f1491, 0x9b50f8850fd58892, 0x4975488358b74de8,
0xa3354ff691531c61, 0x0702bbe481d2c6ee, 0x89fb24057deded98, 0xac3075138596e902,
0x1d2d3580172772ed, 0xeb738fc28e6bc30d, 0x5854ef8f63044326, 0x9e5c52325add3bbe,
0x90aa53cf325c4623, 0xc1d24d51349dd067, 0x2051cfeea69ea624, 0x13220f0a862e7e4f,
0xce39399404e04864, 0xd9c42ca47086fcb7, 0x685ad2238a03e7cc, 0x066484b2ab2ff1db,
0xfe9d5d70efbf79ec, 0x5b13b9dd9c481854, 0x15f0d475ed1509ad, 0x0bebcd060ec79851,
0xd58c6791183ab7f8, 0xd1187c5052f3eee4, 0xc95d1192e54e82ff, 0x86eea14cb9ac6ca2,
0x3485beb153677d5d, 0xdd191d781f8c492a, 0xf60866baa784ebf9, 0x518f643ba2d08c74,
0x8852e956e1087c22, 0xa768cb8dc410ae8d, 0x38047726bfec8e1a, 0xa67738b4cd3b45aa,
0xad16691cec0dde19, 0xc6d4319380462e07, 0xc5a5876d0ba61938, 0x16b9fa1fa58fd840,
0x188ab1173ca74f18, 0xabda2f98c99c021f, 0x3e0580ab134ae816, 0x5f3b05b773645abb,
0x2501a2be5575f2f6, 0x1b2f74004e7e8ba9, 0x1cd7580371e8d953, 0x7f6ed89562764e30,
0xb15926ff596f003d, 0x9f65293da8c5d6b9, 0x6ecef04dd690f84c, 0x4782275fff33af88,
0xe41433083f820801, 0xfd0dfe409a1af9b5, 0x4325a3342cdb396b, 0x8ae77e62b301b252,
0xc36f9e9f6655615a, 0x85455a2d92d32c09, 0xf2c7dea949477485, 0x63cfb4c133a39eba,
0x83b040cc6ebc5462, 0x3b9454c8fdb326b0, 0x56f56a9e87ffd78c, 0x2dc2940d99f42bc6,
0x98f7df096b096e2d, 0x19a6e01e3ad852bf, 0x42a99ccbdbd4b40b, 0xa59998af45e9c559,
0x366295e807d93186, 0x6b48181bfaa1f773, 0x1fec57e2157a0a1d, 0x4667446af6201ad5,
0xe615ebcacfb0f075, 0xb8f31f4f68290778, 0x22713ed6ce22d11e, 0x3057c1a72ec3c93b,
0xcb46acc37c3f1f2f, 0xdbb893fd02aaf50e, 0x331fd92e600b9fcf, 0xa498f96148ea3ad6,
0xa8d8426e8b6a83ea, 0xa089b274b7735cdc, 0x87f6b3731e524a11, 0x118808e5cbc96749,
0x9906e4c7b19bd394, 0xafed7f7e9b24a20c, 0x6509eadeeb3644a7, 0x6c1ef1d3e8ef0ede,
0xb9c97d43e9798fb4, 0xa2f2d784740c28a3, 0x7b8496476197566f, 0x7a5be3e6b65f069d,
0xf96330ed78be6f10, 0xeee60de77a076a15, 0x2b4bee4aa08b9bd0, 0x6a56a63ec7b8894e,
0x02121359ba34fef4, 0x4cbf99f8283703fc, 0x398071350caf30c8, 0xd0a77a89f017687a,
0xf1c1a9eb9e423569, 0x8c7976282dee8199, 0x5d1737a5dd1f7abd, 0x4f53433c09a9fa80,
0xfa8b0c53df7ca1d9, 0x3fd9dcbc886ccb77, 0xc040917ca91b4720, 0x7dd00142f9d1dcdf,
0x8476fc1d4f387b58, 0x23f8e7c5f3316503, 0x032a2244e7e37339, 0x5c87a5d750f5a74b,
0x082b4cc43698992e, 0xdf917becb858f63c, 0x3270b8fc5bf86dda, 0x10ae72bb29b5dd76,
0x576ac94e7700362b, 0x1ad112dac61efb8f, 0x691bc30ec5faa427, 0xff246311cc327143,
0x3142368e30e53206, 0x71380e31e02ca396, 0x958d5c960aad76f1, 0xf8d6f430c16da536,
0xc8ffd13f1be7e1d2, 0x7578ae66004ddbe1, 0x05833f01067be646, 0xbb34b5ad3bfe586d,
0x095f34c9a12b97f0, 0x247ab64525d60ca8, 0xdcdbc6f3017477d1, 0x4a2e14d4decad24d,
0xbdb5e6d9be0a1eeb, 0x2a7e70f7794301ab, 0xdef42d8a270540fd, 0x01078ec0a34c22c1,
0xe5de511af4c16387, 0x7ebb3a52bd9a330a, 0x77697857aa7d6435, 0x004e831603ae4c32,
0xe7a21020ad78e312, 0x9d41a70c6ab420f2, 0x28e06c18ea1141e6, 0xd2b28cbd984f6b28,
0x26b75f6c446e9d83, 0xba47568c4d418d7f, 0xd80badbfe6183d8e, 0x0e206d7f5f166044,
0xe258a43911cbca3e, 0x723a1746b21dc0bc, 0xc7caa854f5d7cdd3, 0x7cac32883d261d9c,
0x7690c26423ba942c, 0x17e55524478042b8, 0xe0be477656a2389f, 0x4d289b5e67ab2da0,
0x44862b9c8fbbfd31, 0xb47cc8049d141365, 0x822c1b362b91c793, 0x4eb14655fb13dfd8,
0x1ecbba0714e2a97b, 0x6143459d5cde5f14, 0x53a8fbf1d5f0ac89, 0x97ea04d81c5e5b00,
0x622181a8d4fdb3f3, 0xe9bcd341572a1208, 0x1411258643cce58a, 0x9144c5fea4c6e0a4,
0x0d33d06565cf620f, 0x54a48d489f219ca1, 0xc43e5eac6d63c821, 0xa9728b3a72770daf,
0xd7934e7b20df87ef, 0xe35503b61a3e86e5, 0xcae321fbc819d504, 0x129a50b3ac60bfa6,
0xcd5e68ea7e9fb6c3, 0xb01c90199483b1c7, 0x3de93cd5c295376c, 0xaed52edf2ab9ad13,
0x2e60f512c0a07884, 0xbc3d86a3e36210c9, 0x35269d9b163951ce, 0x0c7d6e2ad0cdb5fa,
0x59e86297d87f5733, 0x298ef221898db0e7, 0x55000029d1a5aa7e, 0x8bc08ae1b5061b45,
0xc2c31c2b6c92703a, 0x94cc596baf25ef42, 0x0a1d73db22540456, 0x04b6a0f9d9c4179a,
0xeffdafa2ae3d3c60, 0xf7c8075bb49496c4, 0x9cc5c7141d1cd4e3, 0x78bd1638218e5534,
0xb2f11568f850246a, 0xedfabcfa9502bc29, 0x796ce5f2da23051b, 0xaae128b0dc93537c,
0x3a493da0ee4b29ae, 0xb5df6b2c416895d7, 0xfcabbd25122d7f37, 0x70810b58105dc4b1,
0xe10fdd37f7882a90, 0x524dcab5518a3f5c, 0x3c9e85878451255b, 0x4029828119bd34e2,
0x74a05b6f5d3ceccb, 0xb610021542e13eca, 0x0ff979d12f59e2ac, 0x6037da27e4f9cc50,
0x5e92975a0df1847d, 0xd66de190d3e623fe, 0x5032d6b87b568048, 0x9a36b7ce8235216e,
0x80272a7a24f64b4a, 0x93efed8b8c6916f7, 0x37ddbff44cce1555, 0x4b95db5d4b99bd25,
0x92d3fda169812fc0, 0xfb1a4a9a90660bb6, 0x730c196946a4b9b2, 0x81e289aa7f49da68,
0x64669a0f83b1a05f, 0x27b3ff7d9644f48b, 0xcc6b615c8db675b3, 0x674f20b9bcebbe95,
0x6f31238275655982, 0x5ae488713e45cf05, 0xbf619f9954c21157, 0xeabac46040a8eae9,
0x454c6fe9f2c0c1cd, 0x419cf6496412691c, 0xd3dc3bef265b0f70, 0x6d0e60f5c3578a9e,
}
T4 := [?]u64 {
0x5b0e608526323c55, 0x1a46c1a9fa1b59f5, 0xa9e245a17c4c8ffa, 0x65ca5159db2955d7,
0x05db0a76ce35afc2, 0x81eac77ea9113d45, 0x528ef88ab6ac0a0d, 0xa09ea253597be3ff,
0x430ddfb3ac48cd56, 0xc4b3a67af45ce46f, 0x4ececfd8fbe2d05e, 0x3ef56f10b39935f0,
0x0b22d6829cd619c6, 0x17fd460a74df2069, 0x6cf8cc8e8510ed40, 0xd6c824bf3a6ecaa7,
0x61243d581a817049, 0x048bacb6bbc163a2, 0xd9a38ac27d44cc32, 0x7fddff5baaf410ab,
0xad6d495aa804824b, 0xe1a6a74f2d8c9f94, 0xd4f7851235dee8e3, 0xfd4b7f886540d893,
0x247c20042aa4bfda, 0x096ea1c517d1327c, 0xd56966b4361a6685, 0x277da5c31221057d,
0x94d59893a43acff7, 0x64f0c51ccdc02281, 0x3d33bcc4ff6189db, 0xe005cb184ce66af1,
0xff5ccd1d1db99bea, 0xb0b854a7fe42980f, 0x7bd46a6a718d4b9f, 0xd10fa8cc22a5fd8c,
0xd31484952be4bd31, 0xc7fa975fcb243847, 0x4886ed1e5846c407, 0x28cddb791eb70b04,
0xc2b00be2f573417f, 0x5c9590452180f877, 0x7a6bddfff370eb00, 0xce509e38d6d9d6a4,
0xebeb0f00647fa702, 0x1dcc06cf76606f06, 0xe4d9f28ba286ff0a, 0xd85a305dc918c262,
0x475b1d8732225f54, 0x2d4fb51668ccb5fe, 0xa679b9d9d72bba20, 0x53841c0d912d43a5,
0x3b7eaa48bf12a4e8, 0x781e0e47f22f1ddf, 0xeff20ce60ab50973, 0x20d261d19dffb742,
0x16a12b03062a2e39, 0x1960eb2239650495, 0x251c16fed50eb8b8, 0x9ac0c330f826016e,
0xed152665953e7671, 0x02d63194a6369570, 0x5074f08394b1c987, 0x70ba598c90b25ce1,
0x794a15810b9742f6, 0x0d5925e9fcaf8c6c, 0x3067716cd868744e, 0x910ab077e8d7731b,
0x6a61bbdb5ac42f61, 0x93513efbf0851567, 0xf494724b9e83e9d5, 0xe887e1985c09648d,
0x34b1d3c675370cfd, 0xdc35e433bc0d255d, 0xd0aab84234131be0, 0x08042a50b48b7eaf,
0x9997c4ee44a3ab35, 0x829a7b49201799d0, 0x263b8307b7c54441, 0x752f95f4fd6a6ca6,
0x927217402c08c6e5, 0x2a8ab754a795d9ee, 0xa442f7552f72943d, 0x2c31334e19781208,
0x4fa98d7ceaee6291, 0x55c3862f665db309, 0xbd0610175d53b1f3, 0x46fe6cb840413f27,
0x3fe03792df0cfa59, 0xcfe700372eb85e8f, 0xa7be29e7adbce118, 0xe544ee5cde8431dd,
0x8a781b1b41f1873e, 0xa5c94c78a0d2f0e7, 0x39412e2877b60728, 0xa1265ef3afc9a62c,
0xbcc2770c6a2506c5, 0x3ab66dd5dce1ce12, 0xe65499d04a675b37, 0x7d8f523481bfd216,
0x0f6f64fcec15f389, 0x74efbe618b5b13c8, 0xacdc82b714273e1d, 0xdd40bfe003199d17,
0x37e99257e7e061f8, 0xfa52626904775aaa, 0x8bbbf63a463d56f9, 0xf0013f1543a26e64,
0xa8307e9f879ec898, 0xcc4c27a4150177cc, 0x1b432f2cca1d3348, 0xde1d1f8f9f6fa013,
0x606602a047a7ddd6, 0xd237ab64cc1cb2c7, 0x9b938e7225fcd1d3, 0xec4e03708e0ff476,
0xfeb2fbda3d03c12d, 0xae0bced2ee43889a, 0x22cb8923ebfb4f43, 0x69360d013cf7396d,
0x855e3602d2d4e022, 0x073805bad01f784c, 0x33e17a133852f546, 0xdf4874058ac7b638,
0xba92b29c678aa14a, 0x0ce89fc76cfaadcd, 0x5f9d4e0908339e34, 0xf1afe9291f5923b9,
0x6e3480f60f4a265f, 0xeebf3a2ab29b841c, 0xe21938a88f91b4ad, 0x57dfeff845c6d3c3,
0x2f006b0bf62caaf2, 0x62f479ef6f75ee78, 0x11a55ad41c8916a9, 0xf229d29084fed453,
0x42f1c27b16b000e6, 0x2b1f76749823c074, 0x4b76eca3c2745360, 0x8c98f463b91691bd,
0x14bcc93cf1ade66a, 0x8885213e6d458397, 0x8e177df0274d4711, 0xb49b73b5503f2951,
0x10168168c3f96b6b, 0x0e3d963b63cab0ae, 0x8dfc4b5655a1db14, 0xf789f1356e14de5c,
0x683e68af4e51dac1, 0xc9a84f9d8d4b0fd9, 0x3691e03f52a0f9d1, 0x5ed86e46e1878e80,
0x3c711a0e99d07150, 0x5a0865b20c4e9310, 0x56fbfc1fe4f0682e, 0xea8d5de3105edf9b,
0x71abfdb12379187a, 0x2eb99de1bee77b9c, 0x21ecc0ea33cf4523, 0x59a4d7521805c7a1,
0x3896f5eb56ae7c72, 0xaa638f3db18f75dc, 0x9f39358dabe9808e, 0xb7defa91c00b72ac,
0x6b5541fd62492d92, 0x6dc6dee8f92e4d5b, 0x353f57abc4beea7e, 0x735769d6da5690ce,
0x0a234aa642391484, 0xf6f9508028f80d9d, 0xb8e319a27ab3f215, 0x31ad9c1151341a4d,
0x773c22a57bef5805, 0x45c7561a07968633, 0xf913da9e249dbe36, 0xda652d9b78a64c68,
0x4c27a97f3bc334ef, 0x76621220e66b17f4, 0x967743899acd7d0b, 0xf3ee5bcae0ed6782,
0x409f753600c879fc, 0x06d09a39b5926db6, 0x6f83aeb0317ac588, 0x01e6ca4a86381f21,
0x66ff3462d19f3025, 0x72207c24ddfd3bfb, 0x4af6b6d3e2ece2eb, 0x9c994dbec7ea08de,
0x49ace597b09a8bc4, 0xb38c4766cf0797ba, 0x131b9373c57c2a75, 0xb1822cce61931e58,
0x9d7555b909ba1c0c, 0x127fafdd937d11d2, 0x29da3badc66d92e4, 0xa2c1d57154c2ecbc,
0x58c5134d82f6fe24, 0x1c3ae3515b62274f, 0xe907c82e01cb8126, 0xf8ed091913e37fcb,
0x3249d8f9c80046c9, 0x80cf9bede388fb63, 0x1881539a116cf19e, 0x5103f3f76bd52457,
0x15b7e6f5ae47f7a8, 0xdbd7c6ded47e9ccf, 0x44e55c410228bb1a, 0xb647d4255edb4e99,
0x5d11882bb8aafc30, 0xf5098bbb29d3212a, 0x8fb5ea14e90296b3, 0x677b942157dd025a,
0xfb58e7c0a390acb5, 0x89d3674c83bd4a01, 0x9e2da4df4bf3b93b, 0xfcc41e328cab4829,
0x03f38c96ba582c52, 0xcad1bdbd7fd85db2, 0xbbb442c16082ae83, 0xb95fe86ba5da9ab0,
0xb22e04673771a93f, 0x845358c9493152d8, 0xbe2a488697b4541e, 0x95a2dc2dd38e6966,
0xc02c11ac923c852b, 0x2388b1990df2a87b, 0x7c8008fa1b4f37be, 0x1f70d0c84d54e503,
0x5490adec7ece57d4, 0x002b3c27d9063a3a, 0x7eaea3848030a2bf, 0xc602326ded2003c0,
0x83a7287d69a94086, 0xc57a5fcb30f57a8a, 0xb56844e479ebe779, 0xa373b40f05dcbce9,
0xd71a786e88570ee2, 0x879cbacdbde8f6a0, 0x976ad1bcc164a32f, 0xab21e25e9666d78b,
0x901063aae5e5c33c, 0x9818b34448698d90, 0xe36487ae3e1e8abb, 0xafbdf931893bdcb4,
0x6345a0dc5fbbd519, 0x8628fe269b9465ca, 0x1e5d01603f9c51ec, 0x4de44006a15049b7,
0xbf6c70e5f776cbb1, 0x411218f2ef552bed, 0xcb0c0708705a36a3, 0xe74d14754f986044,
0xcd56d9430ea8280e, 0xc12591d7535f5065, 0xc83223f1720aef96, 0xc3a0396f7363a51f,
}
Tiger_Context :: struct {
a: u64,
b: u64,
c: u64,
x: [64]byte,
nx: int,
length: u64,
ver: int,
}
round :: #force_inline proc "contextless" (a, b, c, x, mul: u64) -> (u64, u64, u64) {
a, b, c := a, b, c
c ~= x
a -= T1[c & 0xff] ~ T2[(c >> 16) & 0xff] ~ T3[(c >> 32) & 0xff] ~ T4[(c >> 48) & 0xff]
b += T4[(c >> 8) & 0xff] ~ T3[(c >> 24) & 0xff] ~ T2[(c >> 40) & 0xff] ~ T1[(c >> 56) & 0xff]
b *= mul
return a, b, c
}
pass :: #force_inline proc "contextless" (a, b, c: u64, d: []u64, mul: u64) -> (x, y, z: u64) {
x, y, z = round(a, b, c, d[0], mul)
y, z, x = round(y, z, x, d[1], mul)
z, x, y = round(z, x, y, d[2], mul)
x, y, z = round(x, y, z, d[3], mul)
y, z, x = round(y, z, x, d[4], mul)
z, x, y = round(z, x, y, d[5], mul)
x, y, z = round(x, y, z, d[6], mul)
y, z, x = round(y, z, x, d[7], mul)
return
}
key_schedule :: #force_inline proc "contextless" (x: []u64) {
x[0] -= x[7] ~ 0xa5a5a5a5a5a5a5a5
x[1] ~= x[0]
x[2] += x[1]
x[3] -= x[2] ~ ((~x[1]) << 19)
x[4] ~= x[3]
x[5] += x[4]
x[6] -= x[5] ~ ((~x[4]) >> 23)
x[7] ~= x[6]
x[0] += x[7]
x[1] -= x[0] ~ ((~x[7]) << 19)
x[2] ~= x[1]
x[3] += x[2]
x[4] -= x[3] ~ ((~x[2]) >> 23)
x[5] ~= x[4]
x[6] += x[5]
x[7] -= x[6] ~ 0x0123456789abcdef
}
compress :: #force_inline proc "contextless" (ctx: ^Tiger_Context, data: []byte) {
a := ctx.a
b := ctx.b
c := ctx.c
x := util.cast_slice([]u64, data)
ctx.a, ctx.b, ctx.c = pass(ctx.a, ctx.b, ctx.c, x, 5)
key_schedule(x)
ctx.c, ctx.a, ctx.b = pass(ctx.c, ctx.a, ctx.b, x, 7)
key_schedule(x)
ctx.b, ctx.c, ctx.a = pass(ctx.b, ctx.c, ctx.a, x, 9)
ctx.a ~= a
ctx.b -= b
ctx.c += c
}
init :: proc "contextless" (ctx: ^Tiger_Context) {
ctx.a = 0x0123456789abcdef
ctx.b = 0xfedcba9876543210
ctx.c = 0xf096a5b4c3b2e187
}
update :: proc(ctx: ^Tiger_Context, input: []byte) {
p := make([]byte, len(input))
copy(p, input)
length := len(p)
ctx.length += u64(length)
if ctx.nx > 0 {
n := len(p)
if n > 64 - ctx.nx {
n = 64 - ctx.nx
}
copy(ctx.x[ctx.nx:ctx.nx + n], p[:n])
ctx.nx += n
if ctx.nx == 64 {
compress(ctx, ctx.x[:64 - 1])
ctx.nx = 0
}
p = p[n:]
}
for len(p) >= 64 {
compress(ctx, p[:64])
p = p[64:]
}
if len(p) > 0 {
ctx.nx = copy(ctx.x[:], p)
}
}
final :: proc(ctx: ^Tiger_Context, hash: []byte) {
length := ctx.length
tmp: [64]byte
if ctx.ver == 1 {
tmp[0] = 0x01
} else {
tmp[0] = 0x80
}
size := length & 0x3f
if size < 56 {
update(ctx, tmp[:56 - size])
} else {
update(ctx, tmp[:64 + 56 - size])
}
length <<= 3
for i := uint(0); i < 8; i += 1 {
tmp[i] = byte(length >> (8 * i))
}
update(ctx, tmp[:8])
for i := uint(0); i < 8; i += 1 {
tmp[i] = byte(ctx.a >> (8 * i))
tmp[i + 8] = byte(ctx.b >> (8 * i))
tmp[i + 16] = byte(ctx.c >> (8 * i))
}
copy(hash[:], tmp[:len(hash)])
}
+726
View File
@@ -0,0 +1,726 @@
package blake
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the BLAKE hashing algorithm, as defined in <https://web.archive.org/web/20190915215948/https://131002.net/blake>
*/
import "core:os"
import "core:io"
/*
High level API
*/
DIGEST_SIZE_224 :: 28
DIGEST_SIZE_256 :: 32
DIGEST_SIZE_384 :: 48
DIGEST_SIZE_512 :: 64
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc "contextless" (data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
}
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: Blake256_Context
ctx.is224 = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
ctx: Blake256_Context
ctx.is224 = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: Blake256_Context
ctx.is224 = true
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc "contextless" (data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Blake256_Context
ctx.is224 = false
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
ctx: Blake256_Context
ctx.is224 = false
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Blake256_Context
ctx.is224 = false
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc "contextless" (data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: Blake512_Context
ctx.is384 = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
ctx: Blake512_Context
ctx.is384 = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: Blake512_Context
ctx.is384 = true
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc "contextless" (data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: Blake512_Context
ctx.is384 = false
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
ctx: Blake512_Context
ctx.is384 = false
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: Blake512_Context
ctx.is384 = false
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
/*
Low level API
*/
init :: proc "contextless" (ctx: ^$T) {
when T == Blake256_Context {
if ctx.is224 {
ctx.h[0] = 0xc1059ed8
ctx.h[1] = 0x367cd507
ctx.h[2] = 0x3070dd17
ctx.h[3] = 0xf70e5939
ctx.h[4] = 0xffc00b31
ctx.h[5] = 0x68581511
ctx.h[6] = 0x64f98fa7
ctx.h[7] = 0xbefa4fa4
} else {
ctx.h[0] = 0x6a09e667
ctx.h[1] = 0xbb67ae85
ctx.h[2] = 0x3c6ef372
ctx.h[3] = 0xa54ff53a
ctx.h[4] = 0x510e527f
ctx.h[5] = 0x9b05688c
ctx.h[6] = 0x1f83d9ab
ctx.h[7] = 0x5be0cd19
}
} else when T == Blake512_Context {
if ctx.is384 {
ctx.h[0] = 0xcbbb9d5dc1059ed8
ctx.h[1] = 0x629a292a367cd507
ctx.h[2] = 0x9159015a3070dd17
ctx.h[3] = 0x152fecd8f70e5939
ctx.h[4] = 0x67332667ffc00b31
ctx.h[5] = 0x8eb44a8768581511
ctx.h[6] = 0xdb0c2e0d64f98fa7
ctx.h[7] = 0x47b5481dbefa4fa4
} else {
ctx.h[0] = 0x6a09e667f3bcc908
ctx.h[1] = 0xbb67ae8584caa73b
ctx.h[2] = 0x3c6ef372fe94f82b
ctx.h[3] = 0xa54ff53a5f1d36f1
ctx.h[4] = 0x510e527fade682d1
ctx.h[5] = 0x9b05688c2b3e6c1f
ctx.h[6] = 0x1f83d9abfb41bd6b
ctx.h[7] = 0x5be0cd19137e2179
}
}
}
update :: proc "contextless" (ctx: ^$T, data: []byte) {
data := data
when T == Blake256_Context {
if ctx.nx > 0 {
n := copy(ctx.x[ctx.nx:], data)
ctx.nx += n
if ctx.nx == BLOCKSIZE_256 {
block256(ctx, ctx.x[:])
ctx.nx = 0
}
data = data[n:]
}
if len(data) >= BLOCKSIZE_256 {
n := len(data) &~ (BLOCKSIZE_256 - 1)
block256(ctx, data[:n])
data = data[n:]
}
if len(data) > 0 {
ctx.nx = copy(ctx.x[:], data)
}
} else when T == Blake512_Context {
if ctx.nx > 0 {
n := copy(ctx.x[ctx.nx:], data)
ctx.nx += n
if ctx.nx == BLOCKSIZE_512 {
block512(ctx, ctx.x[:])
ctx.nx = 0
}
data = data[n:]
}
if len(data) >= BLOCKSIZE_512 {
n := len(data) &~ (BLOCKSIZE_512 - 1)
block512(ctx, data[:n])
data = data[n:]
}
if len(data) > 0 {
ctx.nx = copy(ctx.x[:], data)
}
}
}
final :: proc "contextless" (ctx: ^$T, hash: []byte) {
when T == Blake256_Context {
tmp: [65]byte
} else when T == Blake512_Context {
tmp: [129]byte
}
nx := u64(ctx.nx)
tmp[0] = 0x80
length := (ctx.t + nx) << 3
when T == Blake256_Context {
if nx == 55 {
if ctx.is224 {
write_additional(ctx, {0x80})
} else {
write_additional(ctx, {0x81})
}
} else {
if nx < 55 {
if nx == 0 {
ctx.nullt = true
}
write_additional(ctx, tmp[0 : 55 - nx])
} else {
write_additional(ctx, tmp[0 : 64 - nx])
write_additional(ctx, tmp[1:56])
ctx.nullt = true
}
if ctx.is224 {
write_additional(ctx, {0x00})
} else {
write_additional(ctx, {0x01})
}
}
for i : uint = 0; i < 8; i += 1 {
tmp[i] = byte(length >> (56 - 8 * i))
}
write_additional(ctx, tmp[0:8])
h := ctx.h[:]
if ctx.is224 {
h = h[0:7]
}
for s, i in h {
hash[i * 4] = byte(s >> 24)
hash[i * 4 + 1] = byte(s >> 16)
hash[i * 4 + 2] = byte(s >> 8)
hash[i * 4 + 3] = byte(s)
}
} else when T == Blake512_Context {
if nx == 111 {
if ctx.is384 {
write_additional(ctx, {0x80})
} else {
write_additional(ctx, {0x81})
}
} else {
if nx < 111 {
if nx == 0 {
ctx.nullt = true
}
write_additional(ctx, tmp[0 : 111 - nx])
} else {
write_additional(ctx, tmp[0 : 128 - nx])
write_additional(ctx, tmp[1:112])
ctx.nullt = true
}
if ctx.is384 {
write_additional(ctx, {0x00})
} else {
write_additional(ctx, {0x01})
}
}
for i : uint = 0; i < 16; i += 1 {
tmp[i] = byte(length >> (120 - 8 * i))
}
write_additional(ctx, tmp[0:16])
h := ctx.h[:]
if ctx.is384 {
h = h[0:6]
}
for s, i in h {
hash[i * 8] = byte(s >> 56)
hash[i * 8 + 1] = byte(s >> 48)
hash[i * 8 + 2] = byte(s >> 40)
hash[i * 8 + 3] = byte(s >> 32)
hash[i * 8 + 4] = byte(s >> 24)
hash[i * 8 + 5] = byte(s >> 16)
hash[i * 8 + 6] = byte(s >> 8)
hash[i * 8 + 7] = byte(s)
}
}
}
SIZE_224 :: 28
SIZE_256 :: 32
SIZE_384 :: 48
SIZE_512 :: 64
BLOCKSIZE_256 :: 64
BLOCKSIZE_512 :: 128
Blake256_Context :: struct {
h: [8]u32,
s: [4]u32,
t: u64,
x: [64]byte,
nx: int,
is224: bool,
nullt: bool,
}
Blake512_Context :: struct {
h: [8]u64,
s: [4]u64,
t: u64,
x: [128]byte,
nx: int,
is384: bool,
nullt: bool,
}
SIGMA := [?]int {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
}
U256 := [16]u32 {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
}
U512 := [16]u64 {
0x243f6a8885a308d3, 0x13198a2e03707344, 0xa4093822299f31d0, 0x082efa98ec4e6c89,
0x452821e638d01377, 0xbe5466cf34e90c6c, 0xc0ac29b7c97c50dd, 0x3f84d5b5b5470917,
0x9216d5d98979fb1b, 0xd1310ba698dfb5ac, 0x2ffd72dbd01adfb7, 0xb8e1afed6a267e96,
0xba7c9045f12c7f99, 0x24a19947b3916cf7, 0x0801f2e2858efc16, 0x636920d871574e69,
}
G256 :: #force_inline proc "contextless" (a, b, c, d: u32, m: [16]u32, i, j: int) -> (u32, u32, u32, u32) {
a, b, c, d := a, b, c, d
a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
a += b
d ~= a
d = d << (32 - 16) | d >> 16
c += d
b ~= c
b = b << (32 - 12) | b >> 12
a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U256[SIGMA[(i % 10) * 16 + (2 * j)]]
a += b
d ~= a
d = d << (32 - 8) | d >> 8
c += d
b ~= c
b = b << (32 - 7) | b >> 7
return a, b, c, d
}
G512 :: #force_inline proc "contextless" (a, b, c, d: u64, m: [16]u64, i, j: int) -> (u64, u64, u64, u64) {
a, b, c, d := a, b, c, d
a += m[SIGMA[(i % 10) * 16 + (2 * j)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j + 1)]]
a += b
d ~= a
d = d << (64 - 32) | d >> 32
c += d
b ~= c
b = b << (64 - 25) | b >> 25
a += m[SIGMA[(i % 10) * 16 + (2 * j + 1)]] ~ U512[SIGMA[(i % 10) * 16 + (2 * j)]]
a += b
d ~= a
d = d << (64 - 16) | d >> 16
c += d
b ~= c
b = b << (64 - 11) | b >> 11
return a, b, c, d
}
block256 :: proc "contextless" (ctx: ^Blake256_Context, p: []byte) #no_bounds_check {
i, j: int = ---, ---
v, m: [16]u32 = ---, ---
p := p
for len(p) >= BLOCKSIZE_256 {
v[0] = ctx.h[0]
v[1] = ctx.h[1]
v[2] = ctx.h[2]
v[3] = ctx.h[3]
v[4] = ctx.h[4]
v[5] = ctx.h[5]
v[6] = ctx.h[6]
v[7] = ctx.h[7]
v[8] = ctx.s[0] ~ U256[0]
v[9] = ctx.s[1] ~ U256[1]
v[10] = ctx.s[2] ~ U256[2]
v[11] = ctx.s[3] ~ U256[3]
v[12] = U256[4]
v[13] = U256[5]
v[14] = U256[6]
v[15] = U256[7]
ctx.t += 512
if !ctx.nullt {
v[12] ~= u32(ctx.t)
v[13] ~= u32(ctx.t)
v[14] ~= u32(ctx.t >> 32)
v[15] ~= u32(ctx.t >> 32)
}
for i, j = 0, 0; i < 16; i, j = i+1, j+4 {
m[i] = u32(p[j]) << 24 | u32(p[j + 1]) << 16 | u32(p[j + 2]) << 8 | u32(p[j + 3])
}
for i = 0; i < 14; i += 1 {
v[0], v[4], v[8], v[12] = G256(v[0], v[4], v[8], v[12], m, i, 0)
v[1], v[5], v[9], v[13] = G256(v[1], v[5], v[9], v[13], m, i, 1)
v[2], v[6], v[10], v[14] = G256(v[2], v[6], v[10], v[14], m, i, 2)
v[3], v[7], v[11], v[15] = G256(v[3], v[7], v[11], v[15], m, i, 3)
v[0], v[5], v[10], v[15] = G256(v[0], v[5], v[10], v[15], m, i, 4)
v[1], v[6], v[11], v[12] = G256(v[1], v[6], v[11], v[12], m, i, 5)
v[2], v[7], v[8], v[13] = G256(v[2], v[7], v[8], v[13], m, i, 6)
v[3], v[4], v[9], v[14] = G256(v[3], v[4], v[9], v[14], m, i, 7)
}
for i = 0; i < 8; i += 1 {
ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
}
p = p[BLOCKSIZE_256:]
}
}
block512 :: proc "contextless" (ctx: ^Blake512_Context, p: []byte) #no_bounds_check {
i, j: int = ---, ---
v, m: [16]u64 = ---, ---
p := p
for len(p) >= BLOCKSIZE_512 {
v[0] = ctx.h[0]
v[1] = ctx.h[1]
v[2] = ctx.h[2]
v[3] = ctx.h[3]
v[4] = ctx.h[4]
v[5] = ctx.h[5]
v[6] = ctx.h[6]
v[7] = ctx.h[7]
v[8] = ctx.s[0] ~ U512[0]
v[9] = ctx.s[1] ~ U512[1]
v[10] = ctx.s[2] ~ U512[2]
v[11] = ctx.s[3] ~ U512[3]
v[12] = U512[4]
v[13] = U512[5]
v[14] = U512[6]
v[15] = U512[7]
ctx.t += 1024
if !ctx.nullt {
v[12] ~= ctx.t
v[13] ~= ctx.t
v[14] ~= 0
v[15] ~= 0
}
for i, j = 0, 0; i < 16; i, j = i + 1, j + 8 {
m[i] = u64(p[j]) << 56 | u64(p[j + 1]) << 48 | u64(p[j + 2]) << 40 | u64(p[j + 3]) << 32 |
u64(p[j + 4]) << 24 | u64(p[j + 5]) << 16 | u64(p[j + 6]) << 8 | u64(p[j + 7])
}
for i = 0; i < 16; i += 1 {
v[0], v[4], v[8], v[12] = G512(v[0], v[4], v[8], v[12], m, i, 0)
v[1], v[5], v[9], v[13] = G512(v[1], v[5], v[9], v[13], m, i, 1)
v[2], v[6], v[10], v[14] = G512(v[2], v[6], v[10], v[14], m, i, 2)
v[3], v[7], v[11], v[15] = G512(v[3], v[7], v[11], v[15], m, i, 3)
v[0], v[5], v[10], v[15] = G512(v[0], v[5], v[10], v[15], m, i, 4)
v[1], v[6], v[11], v[12] = G512(v[1], v[6], v[11], v[12], m, i, 5)
v[2], v[7], v[8], v[13] = G512(v[2], v[7], v[8], v[13], m, i, 6)
v[3], v[4], v[9], v[14] = G512(v[3], v[4], v[9], v[14], m, i, 7)
}
for i = 0; i < 8; i += 1 {
ctx.h[i] ~= ctx.s[i % 4] ~ v[i] ~ v[i + 8]
}
p = p[BLOCKSIZE_512:]
}
}
write_additional :: proc "contextless" (ctx: ^$T, data: []byte) {
ctx.t -= u64(len(data)) << 3
update(ctx, data)
}
+127
View File
@@ -0,0 +1,127 @@
package blake2b
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the BLAKE2B hashing algorithm.
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
*/
import "core:os"
import "core:io"
import "../_blake2"
/*
High level API
*/
DIGEST_SIZE :: 64
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: _blake2.Blake2b_Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
ctx.cfg = cfg
_blake2.init(&ctx)
_blake2.update(&ctx, data)
_blake2.final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
ctx: _blake2.Blake2b_Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
ctx.cfg = cfg
_blake2.init(&ctx)
_blake2.update(&ctx, data)
_blake2.final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: _blake2.Blake2b_Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
ctx.cfg = cfg
_blake2.init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
_blake2.update(&ctx, buf[:read])
}
}
_blake2.final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
Blake2b_Context :: _blake2.Blake2b_Context
init :: proc(ctx: ^_blake2.Blake2b_Context) {
_blake2.init(ctx)
}
update :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, data: []byte) {
_blake2.update(ctx, data)
}
final :: proc "contextless" (ctx: ^_blake2.Blake2b_Context, hash: []byte) {
_blake2.final(ctx, hash)
}
+127
View File
@@ -0,0 +1,127 @@
package blake2s
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the BLAKE2S hashing algorithm.
BLAKE2B and BLAKE2B share the implementation in the _blake2 package.
*/
import "core:os"
import "core:io"
import "../_blake2"
/*
High level API
*/
DIGEST_SIZE :: 32
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: _blake2.Blake2s_Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
ctx.cfg = cfg
_blake2.init(&ctx)
_blake2.update(&ctx, data)
_blake2.final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
ctx: _blake2.Blake2s_Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
ctx.cfg = cfg
_blake2.init(&ctx)
_blake2.update(&ctx, data)
_blake2.final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: _blake2.Blake2s_Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
ctx.cfg = cfg
_blake2.init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
_blake2.update(&ctx, buf[:read])
}
}
_blake2.final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
Blake2s_Context :: _blake2.Blake2b_Context
init :: proc(ctx: ^_blake2.Blake2s_Context) {
_blake2.init(ctx)
}
update :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, data: []byte) {
_blake2.update(ctx, data)
}
final :: proc "contextless" (ctx: ^_blake2.Blake2s_Context, hash: []byte) {
_blake2.final(ctx, hash)
}
+581
View File
@@ -0,0 +1,581 @@
package chacha20
import "core:crypto/util"
import "core:math/bits"
import "core:mem"
KEY_SIZE :: 32
NONCE_SIZE :: 12
XNONCE_SIZE :: 24
_MAX_CTR_IETF :: 0xffffffff
_BLOCK_SIZE :: 64
_STATE_SIZE_U32 :: 16
_ROUNDS :: 20
_SIGMA_0 : u32 : 0x61707865
_SIGMA_1 : u32 : 0x3320646e
_SIGMA_2 : u32 : 0x79622d32
_SIGMA_3 : u32 : 0x6b206574
Context :: struct {
_s: [_STATE_SIZE_U32]u32,
_buffer: [_BLOCK_SIZE]byte,
_off: int,
_is_ietf_flavor: bool,
_is_initialized: bool,
}
init :: proc (ctx: ^Context, key, nonce: []byte) {
if len(key) != KEY_SIZE {
panic("crypto/chacha20: invalid ChaCha20 key size")
}
if n_len := len(nonce); n_len != NONCE_SIZE && n_len != XNONCE_SIZE {
panic("crypto/chacha20: invalid (X)ChaCha20 nonce size")
}
k, n := key, nonce
// Derive the XChaCha20 subkey and sub-nonce via HChaCha20.
is_xchacha := len(nonce) == XNONCE_SIZE
if is_xchacha {
sub_key := ctx._buffer[:KEY_SIZE]
_hchacha20(sub_key, k, n)
k = sub_key
n = n[16:24]
}
ctx._s[0] = _SIGMA_0
ctx._s[1] = _SIGMA_1
ctx._s[2] = _SIGMA_2
ctx._s[3] = _SIGMA_3
ctx._s[4] = util.U32_LE(k[0:4])
ctx._s[5] = util.U32_LE(k[4:8])
ctx._s[6] = util.U32_LE(k[8:12])
ctx._s[7] = util.U32_LE(k[12:16])
ctx._s[8] = util.U32_LE(k[16:20])
ctx._s[9] = util.U32_LE(k[20:24])
ctx._s[10] = util.U32_LE(k[24:28])
ctx._s[11] = util.U32_LE(k[28:32])
ctx._s[12] = 0
if !is_xchacha {
ctx._s[13] = util.U32_LE(n[0:4])
ctx._s[14] = util.U32_LE(n[4:8])
ctx._s[15] = util.U32_LE(n[8:12])
} else {
ctx._s[13] = 0
ctx._s[14] = util.U32_LE(n[0:4])
ctx._s[15] = util.U32_LE(n[4:8])
// The sub-key is stored in the keystream buffer. While
// this will be overwritten in most circumstances, explicitly
// clear it out early.
mem.zero_explicit(&ctx._buffer, KEY_SIZE)
}
ctx._off = _BLOCK_SIZE
ctx._is_ietf_flavor = !is_xchacha
ctx._is_initialized = true
}
seek :: proc (ctx: ^Context, block_nr: u64) {
assert(ctx._is_initialized)
if ctx._is_ietf_flavor {
if block_nr > _MAX_CTR_IETF {
panic("crypto/chacha20: attempted to seek past maximum counter")
}
} else {
ctx._s[13] = u32(block_nr >> 32)
}
ctx._s[12] = u32(block_nr)
ctx._off = _BLOCK_SIZE
}
xor_bytes :: proc (ctx: ^Context, dst, src: []byte) {
assert(ctx._is_initialized)
// TODO: Enforcing that dst and src alias exactly or not at all
// is a good idea, though odd aliasing should be extremely uncommon.
src, dst := src, dst
if dst_len := len(dst); dst_len < len(src) {
src = src[:dst_len]
}
for remaining := len(src); remaining > 0; {
// Process multiple blocks at once
if ctx._off == _BLOCK_SIZE {
if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 {
direct_bytes := nr_blocks * _BLOCK_SIZE
_do_blocks(ctx, dst, src, nr_blocks)
remaining -= direct_bytes
if remaining == 0 {
return
}
dst = dst[direct_bytes:]
src = src[direct_bytes:]
}
// If there is a partial block, generate and buffer 1 block
// worth of keystream.
_do_blocks(ctx, ctx._buffer[:], nil, 1)
ctx._off = 0
}
// Process partial blocks from the buffered keystream.
to_xor := min(_BLOCK_SIZE - ctx._off, remaining)
buffered_keystream := ctx._buffer[ctx._off:]
for i := 0; i < to_xor; i = i + 1 {
dst[i] = buffered_keystream[i] ~ src[i]
}
ctx._off += to_xor
dst = dst[to_xor:]
src = src[to_xor:]
remaining -= to_xor
}
}
keystream_bytes :: proc (ctx: ^Context, dst: []byte) {
assert(ctx._is_initialized)
dst := dst
for remaining := len(dst); remaining > 0; {
// Process multiple blocks at once
if ctx._off == _BLOCK_SIZE {
if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 {
direct_bytes := nr_blocks * _BLOCK_SIZE
_do_blocks(ctx, dst, nil, nr_blocks)
remaining -= direct_bytes
if remaining == 0 {
return
}
dst = dst[direct_bytes:]
}
// If there is a partial block, generate and buffer 1 block
// worth of keystream.
_do_blocks(ctx, ctx._buffer[:], nil, 1)
ctx._off = 0
}
// Process partial blocks from the buffered keystream.
to_copy := min(_BLOCK_SIZE - ctx._off, remaining)
buffered_keystream := ctx._buffer[ctx._off:]
copy(dst[:to_copy], buffered_keystream[:to_copy])
ctx._off += to_copy
dst = dst[to_copy:]
remaining -= to_copy
}
}
reset :: proc (ctx: ^Context) {
mem.zero_explicit(&ctx._s, size_of(ctx._s))
mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer))
ctx._is_initialized = false
}
_do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
// Enforce the maximum consumed keystream per nonce.
//
// While all modern "standard" definitions of ChaCha20 use
// the IETF 32-bit counter, for XChaCha20 most common
// implementations allow for a 64-bit counter.
//
// Honestly, the answer here is "use a MRAE primitive", but
// go with common practice in the case of XChaCha20.
if ctx._is_ietf_flavor {
if u64(ctx._s[12]) + u64(nr_blocks) > 0xffffffff {
panic("crypto/chacha20: maximum ChaCha20 keystream per nonce reached")
}
} else {
ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12])
if _, carry := bits.add_u64(ctr, u64(nr_blocks), 0); carry != 0 {
panic("crypto/chacha20: maximum XChaCha20 keystream per nonce reached")
}
}
dst, src := dst, src
x := &ctx._s
for n := 0; n < nr_blocks; n = n + 1 {
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
for i := _ROUNDS; i > 0; i = i - 2 {
// Even when forcing inlining manually inlining all of
// these is decently faster.
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ~= x0
x12 = util.ROTL32(x12, 16)
x8 += x12
x4 ~= x8
x4 = util.ROTL32(x4, 12)
x0 += x4
x12 ~= x0
x12 = util.ROTL32(x12, 8)
x8 += x12
x4 ~= x8
x4 = util.ROTL32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ~= x1
x13 = util.ROTL32(x13, 16)
x9 += x13
x5 ~= x9
x5 = util.ROTL32(x5, 12)
x1 += x5
x13 ~= x1
x13 = util.ROTL32(x13, 8)
x9 += x13
x5 ~= x9
x5 = util.ROTL32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ~= x2
x14 = util.ROTL32(x14, 16)
x10 += x14
x6 ~= x10
x6 = util.ROTL32(x6, 12)
x2 += x6
x14 ~= x2
x14 = util.ROTL32(x14, 8)
x10 += x14
x6 ~= x10
x6 = util.ROTL32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ~= x3
x15 = util.ROTL32(x15, 16)
x11 += x15
x7 ~= x11
x7 = util.ROTL32(x7, 12)
x3 += x7
x15 ~= x3
x15 = util.ROTL32(x15, 8)
x11 += x15
x7 ~= x11
x7 = util.ROTL32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ~= x0
x15 = util.ROTL32(x15, 16)
x10 += x15
x5 ~= x10
x5 = util.ROTL32(x5, 12)
x0 += x5
x15 ~= x0
x15 = util.ROTL32(x15, 8)
x10 += x15
x5 ~= x10
x5 = util.ROTL32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ~= x1
x12 = util.ROTL32(x12, 16)
x11 += x12
x6 ~= x11
x6 = util.ROTL32(x6, 12)
x1 += x6
x12 ~= x1
x12 = util.ROTL32(x12, 8)
x11 += x12
x6 ~= x11
x6 = util.ROTL32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ~= x2
x13 = util.ROTL32(x13, 16)
x8 += x13
x7 ~= x8
x7 = util.ROTL32(x7, 12)
x2 += x7
x13 ~= x2
x13 = util.ROTL32(x13, 8)
x8 += x13
x7 ~= x8
x7 = util.ROTL32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ~= x3
x14 = util.ROTL32(x14, 16)
x9 += x14
x4 ~= x9
x4 = util.ROTL32(x4, 12)
x3 += x4
x14 ~= x3
x14 = util.ROTL32(x14, 8)
x9 += x14
x4 ~= x9
x4 = util.ROTL32(x4, 7)
}
x0 += _SIGMA_0
x1 += _SIGMA_1
x2 += _SIGMA_2
x3 += _SIGMA_3
x4 += x[4]
x5 += x[5]
x6 += x[6]
x7 += x[7]
x8 += x[8]
x9 += x[9]
x10 += x[10]
x11 += x[11]
x12 += x[12]
x13 += x[13]
x14 += x[14]
x15 += x[15]
// While the "correct" answer to getting more performance out of
// this is "use vector operations", support for that is currently
// a work in progress/to be designed.
//
// Until dedicated assembly can be written leverage the fact that
// the callers of this routine ensure that src/dst are valid.
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
// systems that also happen to not be strict about aligned
// memory access.
dst_p := transmute(^[16]u32)(&dst[0])
if src != nil {
src_p := transmute(^[16]u32)(&src[0])
dst_p[0] = src_p[0] ~ x0
dst_p[1] = src_p[1] ~ x1
dst_p[2] = src_p[2] ~ x2
dst_p[3] = src_p[3] ~ x3
dst_p[4] = src_p[4] ~ x4
dst_p[5] = src_p[5] ~ x5
dst_p[6] = src_p[6] ~ x6
dst_p[7] = src_p[7] ~ x7
dst_p[8] = src_p[8] ~ x8
dst_p[9] = src_p[9] ~ x9
dst_p[10] = src_p[10] ~ x10
dst_p[11] = src_p[11] ~ x11
dst_p[12] = src_p[12] ~ x12
dst_p[13] = src_p[13] ~ x13
dst_p[14] = src_p[14] ~ x14
dst_p[15] = src_p[15] ~ x15
src = src[_BLOCK_SIZE:]
} else {
dst_p[0] = x0
dst_p[1] = x1
dst_p[2] = x2
dst_p[3] = x3
dst_p[4] = x4
dst_p[5] = x5
dst_p[6] = x6
dst_p[7] = x7
dst_p[8] = x8
dst_p[9] = x9
dst_p[10] = x10
dst_p[11] = x11
dst_p[12] = x12
dst_p[13] = x13
dst_p[14] = x14
dst_p[15] = x15
}
dst = dst[_BLOCK_SIZE:]
} else {
#no_bounds_check {
if src != nil {
util.PUT_U32_LE(dst[0:4], util.U32_LE(src[0:4]) ~ x0)
util.PUT_U32_LE(dst[4:8], util.U32_LE(src[4:8]) ~ x1)
util.PUT_U32_LE(dst[8:12], util.U32_LE(src[8:12]) ~ x2)
util.PUT_U32_LE(dst[12:16], util.U32_LE(src[12:16]) ~ x3)
util.PUT_U32_LE(dst[16:20], util.U32_LE(src[16:20]) ~ x4)
util.PUT_U32_LE(dst[20:24], util.U32_LE(src[20:24]) ~ x5)
util.PUT_U32_LE(dst[24:28], util.U32_LE(src[24:28]) ~ x6)
util.PUT_U32_LE(dst[28:32], util.U32_LE(src[28:32]) ~ x7)
util.PUT_U32_LE(dst[32:36], util.U32_LE(src[32:36]) ~ x8)
util.PUT_U32_LE(dst[36:40], util.U32_LE(src[36:40]) ~ x9)
util.PUT_U32_LE(dst[40:44], util.U32_LE(src[40:44]) ~ x10)
util.PUT_U32_LE(dst[44:48], util.U32_LE(src[44:48]) ~ x11)
util.PUT_U32_LE(dst[48:52], util.U32_LE(src[48:52]) ~ x12)
util.PUT_U32_LE(dst[52:56], util.U32_LE(src[52:56]) ~ x13)
util.PUT_U32_LE(dst[56:60], util.U32_LE(src[56:60]) ~ x14)
util.PUT_U32_LE(dst[60:64], util.U32_LE(src[60:64]) ~ x15)
src = src[_BLOCK_SIZE:]
} else {
util.PUT_U32_LE(dst[0:4], x0)
util.PUT_U32_LE(dst[4:8], x1)
util.PUT_U32_LE(dst[8:12], x2)
util.PUT_U32_LE(dst[12:16], x3)
util.PUT_U32_LE(dst[16:20], x4)
util.PUT_U32_LE(dst[20:24], x5)
util.PUT_U32_LE(dst[24:28], x6)
util.PUT_U32_LE(dst[28:32], x7)
util.PUT_U32_LE(dst[32:36], x8)
util.PUT_U32_LE(dst[36:40], x9)
util.PUT_U32_LE(dst[40:44], x10)
util.PUT_U32_LE(dst[44:48], x11)
util.PUT_U32_LE(dst[48:52], x12)
util.PUT_U32_LE(dst[52:56], x13)
util.PUT_U32_LE(dst[56:60], x14)
util.PUT_U32_LE(dst[60:64], x15)
}
dst = dst[_BLOCK_SIZE:]
}
}
// Increment the counter. Overflow checking is done upon
// entry into the routine, so a 64-bit increment safely
// covers both cases.
new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + 1
x[12] = u32(new_ctr)
x[13] = u32(new_ctr >> 32)
}
}
_hchacha20 :: proc (dst, key, nonce: []byte) {
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
x4 := util.U32_LE(key[0:4])
x5 := util.U32_LE(key[4:8])
x6 := util.U32_LE(key[8:12])
x7 := util.U32_LE(key[12:16])
x8 := util.U32_LE(key[16:20])
x9 := util.U32_LE(key[20:24])
x10 := util.U32_LE(key[24:28])
x11 := util.U32_LE(key[28:32])
x12 := util.U32_LE(nonce[0:4])
x13 := util.U32_LE(nonce[4:8])
x14 := util.U32_LE(nonce[8:12])
x15 := util.U32_LE(nonce[12:16])
for i := _ROUNDS; i > 0; i = i - 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ~= x0
x12 = util.ROTL32(x12, 16)
x8 += x12
x4 ~= x8
x4 = util.ROTL32(x4, 12)
x0 += x4
x12 ~= x0
x12 = util.ROTL32(x12, 8)
x8 += x12
x4 ~= x8
x4 = util.ROTL32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ~= x1
x13 = util.ROTL32(x13, 16)
x9 += x13
x5 ~= x9
x5 = util.ROTL32(x5, 12)
x1 += x5
x13 ~= x1
x13 = util.ROTL32(x13, 8)
x9 += x13
x5 ~= x9
x5 = util.ROTL32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ~= x2
x14 = util.ROTL32(x14, 16)
x10 += x14
x6 ~= x10
x6 = util.ROTL32(x6, 12)
x2 += x6
x14 ~= x2
x14 = util.ROTL32(x14, 8)
x10 += x14
x6 ~= x10
x6 = util.ROTL32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ~= x3
x15 = util.ROTL32(x15, 16)
x11 += x15
x7 ~= x11
x7 = util.ROTL32(x7, 12)
x3 += x7
x15 ~= x3
x15 = util.ROTL32(x15, 8)
x11 += x15
x7 ~= x11
x7 = util.ROTL32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ~= x0
x15 = util.ROTL32(x15, 16)
x10 += x15
x5 ~= x10
x5 = util.ROTL32(x5, 12)
x0 += x5
x15 ~= x0
x15 = util.ROTL32(x15, 8)
x10 += x15
x5 ~= x10
x5 = util.ROTL32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ~= x1
x12 = util.ROTL32(x12, 16)
x11 += x12
x6 ~= x11
x6 = util.ROTL32(x6, 12)
x1 += x6
x12 ~= x1
x12 = util.ROTL32(x12, 8)
x11 += x12
x6 ~= x11
x6 = util.ROTL32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ~= x2
x13 = util.ROTL32(x13, 16)
x8 += x13
x7 ~= x8
x7 = util.ROTL32(x7, 12)
x2 += x7
x13 ~= x2
x13 = util.ROTL32(x13, 8)
x8 += x13
x7 ~= x8
x7 = util.ROTL32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ~= x3
x14 = util.ROTL32(x14, 16)
x9 += x14
x4 ~= x9
x4 = util.ROTL32(x4, 12)
x3 += x4
x14 ~= x3
x14 = util.ROTL32(x14, 8)
x9 += x14
x4 ~= x9
x4 = util.ROTL32(x4, 7)
}
util.PUT_U32_LE(dst[0:4], x0)
util.PUT_U32_LE(dst[4:8], x1)
util.PUT_U32_LE(dst[8:12], x2)
util.PUT_U32_LE(dst[12:16], x3)
util.PUT_U32_LE(dst[16:20], x12)
util.PUT_U32_LE(dst[20:24], x13)
util.PUT_U32_LE(dst[24:28], x14)
util.PUT_U32_LE(dst[28:32], x15)
}
@@ -0,0 +1,146 @@
package chacha20poly1305
import "core:crypto"
import "core:crypto/chacha20"
import "core:crypto/poly1305"
import "core:crypto/util"
import "core:mem"
KEY_SIZE :: chacha20.KEY_SIZE
NONCE_SIZE :: chacha20.NONCE_SIZE
TAG_SIZE :: poly1305.TAG_SIZE
_P_MAX :: 64 * 0xffffffff // 64 * (2^32-1)
_validate_common_slice_sizes :: proc (tag, key, nonce, aad, text: []byte) {
if len(tag) != TAG_SIZE {
panic("crypto/chacha20poly1305: invalid destination tag size")
}
if len(key) != KEY_SIZE {
panic("crypto/chacha20poly1305: invalid key size")
}
if len(nonce) != NONCE_SIZE {
panic("crypto/chacha20poly1305: invalid nonce size")
}
#assert(size_of(int) == 8 || size_of(int) <= 4)
when size_of(int) == 8 {
// A_MAX = 2^64 - 1 due to the length field limit.
// P_MAX = 64 * (2^32 - 1) due to the IETF ChaCha20 counter limit.
//
// A_MAX is limited by size_of(int), so there is no need to
// enforce it. P_MAX only needs to be checked on 64-bit targets,
// for reasons that should be obvious.
if text_len := len(text); text_len > _P_MAX {
panic("crypto/chacha20poly1305: oversized src data")
}
}
}
_PAD: [16]byte
_update_mac_pad16 :: #force_inline proc (ctx: ^poly1305.Context, x_len: int) {
if pad_len := 16 - (x_len & (16-1)); pad_len != 16 {
poly1305.update(ctx, _PAD[:pad_len])
}
}
encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
_validate_common_slice_sizes(tag, key, nonce, aad, plaintext)
if len(ciphertext) != len(plaintext) {
panic("crypto/chacha20poly1305: invalid destination ciphertext size")
}
stream_ctx: chacha20.Context = ---
chacha20.init(&stream_ctx, key, nonce)
// otk = poly1305_key_gen(key, nonce)
otk: [poly1305.KEY_SIZE]byte = ---
chacha20.keystream_bytes(&stream_ctx, otk[:])
mac_ctx: poly1305.Context = ---
poly1305.init(&mac_ctx, otk[:])
mem.zero_explicit(&otk, size_of(otk))
aad_len, ciphertext_len := len(aad), len(ciphertext)
// There is nothing preventing aad and ciphertext from overlapping
// so auth the AAD before encrypting (slightly different from the
// RFC, since the RFC encrypts into a new buffer).
//
// mac_data = aad | pad16(aad)
poly1305.update(&mac_ctx, aad)
_update_mac_pad16(&mac_ctx, aad_len)
// ciphertext = chacha20_encrypt(key, 1, nonce, plaintext)
chacha20.seek(&stream_ctx, 1)
chacha20.xor_bytes(&stream_ctx, ciphertext, plaintext)
chacha20.reset(&stream_ctx) // Don't need the stream context anymore.
// mac_data |= ciphertext | pad16(ciphertext)
poly1305.update(&mac_ctx, ciphertext)
_update_mac_pad16(&mac_ctx, ciphertext_len)
// mac_data |= num_to_8_le_bytes(aad.length)
// mac_data |= num_to_8_le_bytes(ciphertext.length)
l_buf := otk[0:16] // Reuse the scratch buffer.
util.PUT_U64_LE(l_buf[0:8], u64(aad_len))
util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len))
poly1305.update(&mac_ctx, l_buf)
// tag = poly1305_mac(mac_data, otk)
poly1305.final(&mac_ctx, tag) // Implicitly sanitizes context.
}
decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
_validate_common_slice_sizes(tag, key, nonce, aad, ciphertext)
if len(ciphertext) != len(plaintext) {
panic("crypto/chacha20poly1305: invalid destination plaintext size")
}
// Note: Unlike encrypt, this can fail early, so use defer for
// sanitization rather than assuming control flow reaches certain
// points where needed.
stream_ctx: chacha20.Context = ---
chacha20.init(&stream_ctx, key, nonce)
// otk = poly1305_key_gen(key, nonce)
otk: [poly1305.KEY_SIZE]byte = ---
chacha20.keystream_bytes(&stream_ctx, otk[:])
defer chacha20.reset(&stream_ctx)
mac_ctx: poly1305.Context = ---
poly1305.init(&mac_ctx, otk[:])
defer mem.zero_explicit(&otk, size_of(otk))
aad_len, ciphertext_len := len(aad), len(ciphertext)
// mac_data = aad | pad16(aad)
// mac_data |= ciphertext | pad16(ciphertext)
// mac_data |= num_to_8_le_bytes(aad.length)
// mac_data |= num_to_8_le_bytes(ciphertext.length)
poly1305.update(&mac_ctx, aad)
_update_mac_pad16(&mac_ctx, aad_len)
poly1305.update(&mac_ctx, ciphertext)
_update_mac_pad16(&mac_ctx, ciphertext_len)
l_buf := otk[0:16] // Reuse the scratch buffer.
util.PUT_U64_LE(l_buf[0:8], u64(aad_len))
util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len))
poly1305.update(&mac_ctx, l_buf)
// tag = poly1305_mac(mac_data, otk)
derived_tag := otk[0:poly1305.TAG_SIZE] // Reuse the scratch buffer again.
poly1305.final(&mac_ctx, derived_tag) // Implicitly sanitizes context.
// Validate the tag in constant time.
if crypto.compare_constant_time(tag, derived_tag) != 1 {
// Zero out the plaintext, as a defense in depth measure.
mem.zero_explicit(raw_data(plaintext), ciphertext_len)
return false
}
// plaintext = chacha20_decrypt(key, 1, nonce, ciphertext)
chacha20.seek(&stream_ctx, 1)
chacha20.xor_bytes(&stream_ctx, plaintext, ciphertext)
return true
}
+52
View File
@@ -0,0 +1,52 @@
package crypto
import "core:mem"
// compare_constant_time returns 1 iff a and b are equal, 0 otherwise.
//
// The execution time of this routine is constant regardless of the contents
// of the slices being compared, as long as the length of the slices is equal.
// If the length of the two slices is different, it will early-return 0.
compare_constant_time :: proc "contextless" (a, b: []byte) -> int {
// If the length of the slices is different, early return.
//
// This leaks the fact that the slices have a different length,
// but the routine is primarily intended for comparing things
// like MACS and password digests.
n := len(a)
if n != len(b) {
return 0
}
return compare_byte_ptrs_constant_time(raw_data(a), raw_data(b), n)
}
// compare_byte_ptrs_constant_time returns 1 iff the bytes pointed to by
// a and b are equal, 0 otherwise.
//
// The execution time of this routine is constant regardless of the
// contents of the memory being compared.
compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> int {
x := mem.slice_ptr(a, n)
y := mem.slice_ptr(b, n)
v: byte
for i in 0..<n {
v |= x[i] ~ y[i]
}
// After the loop, v == 0 iff a == b. The subtraction will underflow
// iff v == 0, setting the sign-bit, which gets returned.
return int((u32(v)-1) >> 31)
}
// rand_bytes fills the dst buffer with cryptographic entropy taken from
// the system entropy source. This routine will block if the system entropy
// source is not ready yet. All system entropy source failures are treated
// as catastrophic, resulting in a panic.
rand_bytes :: proc (dst: []byte) {
// zero-fill the buffer first
mem.zero_explicit(raw_data(dst), len(dst))
_rand_bytes(dst)
}
+382
View File
@@ -0,0 +1,382 @@
package gost
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the GOST hashing algorithm, as defined in RFC 5831 <https://datatracker.ietf.org/doc/html/rfc5831>
*/
import "core:mem"
import "core:os"
import "core:io"
/*
High level API
*/
DIGEST_SIZE :: 32
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Gost_Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
ctx: Gost_Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Gost_Context
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
init :: proc "contextless" (ctx: ^Gost_Context) {
sbox: [8][16]u32 = {
{ 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15 },
{ 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8 },
{ 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13 },
{ 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3 },
{ 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5 },
{ 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3 },
{ 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11 },
{ 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12 },
}
i := 0
for a := 0; a < 16; a += 1 {
ax := sbox[1][a] << 15
bx := sbox[3][a] << 23
cx := sbox[5][a]
cx = (cx >> 1) | (cx << 31)
dx := sbox[7][a] << 7
for b := 0; b < 16; b, i = b + 1, i + 1 {
SBOX_1[i] = ax | (sbox[0][b] << 11)
SBOX_2[i] = bx | (sbox[2][b] << 19)
SBOX_3[i] = cx | (sbox[4][b] << 27)
SBOX_4[i] = dx | (sbox[6][b] << 3)
}
}
}
update :: proc(ctx: ^Gost_Context, data: []byte) {
length := byte(len(data))
j: byte
i := ctx.partial_bytes
for i < 32 && j < length {
ctx.partial[i] = data[j]
i, j = i + 1, j + 1
}
if i < 32 {
ctx.partial_bytes = i
return
}
bytes(ctx, ctx.partial[:], 256)
for (j + 32) < length {
bytes(ctx, data[j:], 256)
j += 32
}
i = 0
for j < length {
ctx.partial[i] = data[j]
i, j = i + 1, j + 1
}
ctx.partial_bytes = i
}
final :: proc(ctx: ^Gost_Context, hash: []byte) {
if ctx.partial_bytes > 0 {
mem.set(&ctx.partial[ctx.partial_bytes], 0, 32 - int(ctx.partial_bytes))
bytes(ctx, ctx.partial[:], u32(ctx.partial_bytes) << 3)
}
compress(ctx.hash[:], ctx.len[:])
compress(ctx.hash[:], ctx.sum[:])
for i, j := 0, 0; i < 8; i, j = i + 1, j + 4 {
hash[j] = byte(ctx.hash[i])
hash[j + 1] = byte(ctx.hash[i] >> 8)
hash[j + 2] = byte(ctx.hash[i] >> 16)
hash[j + 3] = byte(ctx.hash[i] >> 24)
}
}
/*
GOST implementation
*/
Gost_Context :: struct {
sum: [8]u32,
hash: [8]u32,
len: [8]u32,
partial: [32]byte,
partial_bytes: byte,
}
SBOX_1: [256]u32
SBOX_2: [256]u32
SBOX_3: [256]u32
SBOX_4: [256]u32
ENCRYPT_ROUND :: #force_inline proc "contextless" (l, r, t, k1, k2: u32) -> (u32, u32, u32) {
l, r, t := l, r, t
t = (k1) + r
l ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24]
t = (k2) + l
r ~= SBOX_1[t & 0xff] ~ SBOX_2[(t >> 8) & 0xff] ~ SBOX_3[(t >> 16) & 0xff] ~ SBOX_4[t >> 24]
return l, r, t
}
ENCRYPT :: #force_inline proc "contextless" (a, b, c: u32, key: []u32) -> (l, r, t: u32) {
l, r, t = ENCRYPT_ROUND(a, b, c, key[0], key[1])
l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1])
l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
l, r, t = ENCRYPT_ROUND(l, r, t, key[0], key[1])
l, r, t = ENCRYPT_ROUND(l, r, t, key[2], key[3])
l, r, t = ENCRYPT_ROUND(l, r, t, key[4], key[5])
l, r, t = ENCRYPT_ROUND(l, r, t, key[6], key[7])
l, r, t = ENCRYPT_ROUND(l, r, t, key[7], key[6])
l, r, t = ENCRYPT_ROUND(l, r, t, key[5], key[4])
l, r, t = ENCRYPT_ROUND(l, r, t, key[3], key[2])
l, r, t = ENCRYPT_ROUND(l, r, t, key[1], key[0])
t = r
r = l
l = t
return
}
bytes :: proc(ctx: ^Gost_Context, buf: []byte, bits: u32) {
a, c: u32
m: [8]u32
for i, j := 0, 0; i < 8; i += 1 {
a = u32(buf[j]) | u32(buf[j + 1]) << 8 | u32(buf[j + 2]) << 16 | u32(buf[j + 3]) << 24
j += 4
m[i] = a
c = a + c + ctx.sum[i]
ctx.sum[i] = c
c = c < a ? 1 : 0
}
compress(ctx.hash[:], m[:])
ctx.len[0] += bits
if ctx.len[0] < bits {
ctx.len[1] += 1
}
}
compress :: proc(h, m: []u32) {
key, u, v, w, s: [8]u32
copy(u[:], h)
copy(v[:], m)
for i := 0; i < 8; i += 2 {
w[0] = u[0] ~ v[0]
w[1] = u[1] ~ v[1]
w[2] = u[2] ~ v[2]
w[3] = u[3] ~ v[3]
w[4] = u[4] ~ v[4]
w[5] = u[5] ~ v[5]
w[6] = u[6] ~ v[6]
w[7] = u[7] ~ v[7]
key[0] = (w[0] & 0x000000ff) | (w[2] & 0x000000ff) << 8 | (w[4] & 0x000000ff) << 16 | (w[6] & 0x000000ff) << 24
key[1] = (w[0] & 0x0000ff00) >> 8 | (w[2] & 0x0000ff00) | (w[4] & 0x0000ff00) << 8 | (w[6] & 0x0000ff00) << 16
key[2] = (w[0] & 0x00ff0000) >> 16 | (w[2] & 0x00ff0000) >> 8 | (w[4] & 0x00ff0000) | (w[6] & 0x00ff0000) << 8
key[3] = (w[0] & 0xff000000) >> 24 | (w[2] & 0xff000000) >> 16 | (w[4] & 0xff000000) >> 8 | (w[6] & 0xff000000)
key[4] = (w[1] & 0x000000ff) | (w[3] & 0x000000ff) << 8 | (w[5] & 0x000000ff) << 16 | (w[7] & 0x000000ff) << 24
key[5] = (w[1] & 0x0000ff00) >> 8 | (w[3] & 0x0000ff00) | (w[5] & 0x0000ff00) << 8 | (w[7] & 0x0000ff00) << 16
key[6] = (w[1] & 0x00ff0000) >> 16 | (w[3] & 0x00ff0000) >> 8 | (w[5] & 0x00ff0000) | (w[7] & 0x00ff0000) << 8
key[7] = (w[1] & 0xff000000) >> 24 | (w[3] & 0xff000000) >> 16 | (w[5] & 0xff000000) >> 8 | (w[7] & 0xff000000)
r := h[i]
l := h[i + 1]
t: u32
l, r, t = ENCRYPT(l, r, 0, key[:])
s[i] = r
s[i + 1] = l
if i == 6 {
break
}
l = u[0] ~ u[2]
r = u[1] ~ u[3]
u[0] = u[2]
u[1] = u[3]
u[2] = u[4]
u[3] = u[5]
u[4] = u[6]
u[5] = u[7]
u[6] = l
u[7] = r
if i == 2 {
u[0] ~= 0xff00ff00
u[1] ~= 0xff00ff00
u[2] ~= 0x00ff00ff
u[3] ~= 0x00ff00ff
u[4] ~= 0x00ffff00
u[5] ~= 0xff0000ff
u[6] ~= 0x000000ff
u[7] ~= 0xff00ffff
}
l = v[0]
r = v[2]
v[0] = v[4]
v[2] = v[6]
v[4] = l ~ r
v[6] = v[0] ~ r
l = v[1]
r = v[3]
v[1] = v[5]
v[3] = v[7]
v[5] = l ~ r
v[7] = v[1] ~ r
}
u[0] = m[0] ~ s[6]
u[1] = m[1] ~ s[7]
u[2] = m[2] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff) ~
(s[1] & 0xffff) ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[6] ~ (s[6] << 16) ~
(s[7] & 0xffff0000) ~ (s[7] >> 16)
u[3] = m[3] ~ (s[0] & 0xffff) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~
(s[1] << 16) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~
(s[3] << 16) ~ s[6] ~ (s[6] << 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~
(s[7] << 16) ~ (s[7] >> 16)
u[4] = m[4] ~
(s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[0] >> 16) ~
(s[1] & 0xffff0000) ~ (s[1] >> 16) ~ (s[2] << 16) ~ (s[2] >> 16) ~
(s[3] << 16) ~ (s[3] >> 16) ~ (s[4] << 16) ~ (s[6] << 16) ~
(s[6] >> 16) ~(s[7] & 0xffff) ~ (s[7] << 16) ~ (s[7] >> 16)
u[5] = m[5] ~ (s[0] << 16) ~ (s[0] >> 16) ~ (s[0] & 0xffff0000) ~
(s[1] & 0xffff) ~ s[2] ~ (s[2] >> 16) ~ (s[3] << 16) ~ (s[3] >> 16) ~
(s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[6] << 16) ~
(s[6] >> 16) ~ (s[7] & 0xffff0000) ~ (s[7] << 16) ~ (s[7] >> 16)
u[6] = m[6] ~ s[0] ~ (s[1] >> 16) ~ (s[2] << 16) ~ s[3] ~ (s[3] >> 16) ~
(s[4] << 16) ~ (s[4] >> 16) ~ (s[5] << 16) ~ (s[5] >> 16) ~ s[6] ~
(s[6] << 16) ~ (s[6] >> 16) ~ (s[7] << 16)
u[7] = m[7] ~ (s[0] & 0xffff0000) ~ (s[0] << 16) ~ (s[1] & 0xffff) ~
(s[1] << 16) ~ (s[2] >> 16) ~ (s[3] << 16) ~ s[4] ~ (s[4] >> 16) ~
(s[5] << 16) ~ (s[5] >> 16) ~ (s[6] >> 16) ~ (s[7] & 0xffff) ~
(s[7] << 16) ~ (s[7] >> 16)
v[0] = h[0] ~ (u[1] << 16) ~ (u[0] >> 16)
v[1] = h[1] ~ (u[2] << 16) ~ (u[1] >> 16)
v[2] = h[2] ~ (u[3] << 16) ~ (u[2] >> 16)
v[3] = h[3] ~ (u[4] << 16) ~ (u[3] >> 16)
v[4] = h[4] ~ (u[5] << 16) ~ (u[4] >> 16)
v[5] = h[5] ~ (u[6] << 16) ~ (u[5] >> 16)
v[6] = h[6] ~ (u[7] << 16) ~ (u[6] >> 16)
v[7] = h[7] ~ (u[0] & 0xffff0000) ~ (u[0] << 16) ~ (u[7] >> 16) ~ (u[1] & 0xffff0000) ~ (u[1] << 16) ~ (u[6] << 16) ~ (u[7] & 0xffff0000)
h[0] = (v[0] & 0xffff0000) ~ (v[0] << 16) ~ (v[0] >> 16) ~ (v[1] >> 16) ~
(v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ (v[4] << 16) ~
(v[5] >> 16) ~ v[5] ~ (v[6] >> 16) ~ (v[7] << 16) ~ (v[7] >> 16) ~
(v[7] & 0xffff)
h[1] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~ (v[1] & 0xffff) ~
v[2] ~ (v[2] >> 16) ~ (v[3] << 16) ~ (v[4] >> 16) ~ (v[5] << 16) ~
(v[6] << 16) ~ v[6] ~ (v[7] & 0xffff0000) ~ (v[7] >> 16)
h[2] = (v[0] & 0xffff) ~ (v[0] << 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~
(v[1] & 0xffff0000) ~ (v[2] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~
(v[5] >> 16) ~ v[6] ~ (v[6] >> 16) ~ (v[7] & 0xffff) ~ (v[7] << 16) ~
(v[7] >> 16)
h[3] = (v[0] << 16) ~ (v[0] >> 16) ~ (v[0] & 0xffff0000) ~
(v[1] & 0xffff0000) ~ (v[1] >> 16) ~ (v[2] << 16) ~ (v[2] >> 16) ~ v[2] ~
(v[3] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~
(v[7] & 0xffff) ~ (v[7] >> 16)
h[4] = (v[0] >> 16) ~ (v[1] << 16) ~ v[1] ~ (v[2] >> 16) ~ v[2] ~
(v[3] << 16) ~ (v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ (v[5] >> 16) ~
v[5] ~ (v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16)
h[5] = (v[0] << 16) ~ (v[0] & 0xffff0000) ~ (v[1] << 16) ~ (v[1] >> 16) ~
(v[1] & 0xffff0000) ~ (v[2] << 16) ~ v[2] ~ (v[3] >> 16) ~ v[3] ~
(v[4] << 16) ~ (v[4] >> 16) ~ v[4] ~ (v[5] << 16) ~ (v[6] << 16) ~
(v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ (v[7] >> 16) ~ (v[7] & 0xffff0000)
h[6] = v[0] ~ v[2] ~ (v[2] >> 16) ~ v[3] ~ (v[3] << 16) ~ v[4] ~
(v[4] >> 16) ~ (v[5] << 16) ~ (v[5] >> 16) ~ v[5] ~ (v[6] << 16) ~
(v[6] >> 16) ~ v[6] ~ (v[7] << 16) ~ v[7]
h[7] = v[0] ~ (v[0] >> 16) ~ (v[1] << 16) ~ (v[1] >> 16) ~ (v[2] << 16) ~
(v[3] >> 16) ~ v[3] ~ (v[4] << 16) ~ v[4] ~ (v[5] >> 16) ~ v[5] ~
(v[6] << 16) ~ (v[6] >> 16) ~ (v[7] << 16) ~ v[7]
}
+653
View File
@@ -0,0 +1,653 @@
package groestl
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the GROESTL hashing algorithm, as defined in <http://www.groestl.info/Groestl.zip>
*/
import "core:os"
import "core:io"
/*
High level API
*/
DIGEST_SIZE_224 :: 28
DIGEST_SIZE_256 :: 32
DIGEST_SIZE_384 :: 48
DIGEST_SIZE_512 :: 64
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
}
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: Groestl_Context
ctx.hashbitlen = 224
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
ctx: Groestl_Context
ctx.hashbitlen = 224
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: Groestl_Context
ctx.hashbitlen = 224
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Groestl_Context
ctx.hashbitlen = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
ctx: Groestl_Context
ctx.hashbitlen = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Groestl_Context
ctx.hashbitlen = 256
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: Groestl_Context
ctx.hashbitlen = 384
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
ctx: Groestl_Context
ctx.hashbitlen = 384
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: Groestl_Context
ctx.hashbitlen = 384
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: Groestl_Context
ctx.hashbitlen = 512
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
ctx: Groestl_Context
ctx.hashbitlen = 512
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: Groestl_Context
ctx.hashbitlen = 512
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
/*
Low level API
*/
init :: proc(ctx: ^Groestl_Context) {
assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
if ctx.hashbitlen <= 256 {
ctx.rounds = 10
ctx.columns = 8
ctx.statesize = 64
} else {
ctx.rounds = 14
ctx.columns = 16
ctx.statesize = 128
}
for i := 8 - size_of(i32); i < 8; i += 1 {
ctx.chaining[i][ctx.columns - 1] = byte(ctx.hashbitlen >> (8 * (7 - uint(i))))
}
}
update :: proc(ctx: ^Groestl_Context, data: []byte) {
databitlen := len(data) * 8
msglen := databitlen / 8
rem := databitlen % 8
i: int
assert(ctx.bits_in_last_byte == 0)
if ctx.buf_ptr != 0 {
for i = 0; ctx.buf_ptr < ctx.statesize && i < msglen; i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1 {
ctx.buffer[ctx.buf_ptr] = data[i]
}
if ctx.buf_ptr < ctx.statesize {
if rem != 0 {
ctx.bits_in_last_byte = rem
ctx.buffer[ctx.buf_ptr] = data[i]
ctx.buf_ptr += 1
}
return
}
ctx.buf_ptr = 0
transform(ctx, ctx.buffer[:], u32(ctx.statesize))
}
transform(ctx, data[i:], u32(msglen - i))
i += ((msglen - i) / ctx.statesize) * ctx.statesize
for i < msglen {
ctx.buffer[ctx.buf_ptr] = data[i]
i, ctx.buf_ptr = i + 1, ctx.buf_ptr + 1
}
if rem != 0 {
ctx.bits_in_last_byte = rem
ctx.buffer[ctx.buf_ptr] = data[i]
ctx.buf_ptr += 1
}
}
final :: proc(ctx: ^Groestl_Context, hash: []byte) {
hashbytelen := ctx.hashbitlen / 8
if ctx.bits_in_last_byte != 0 {
ctx.buffer[ctx.buf_ptr - 1] &= ((1 << uint(ctx.bits_in_last_byte)) - 1) << (8 - uint(ctx.bits_in_last_byte))
ctx.buffer[ctx.buf_ptr - 1] ~= 0x1 << (7 - uint(ctx.bits_in_last_byte))
} else {
ctx.buffer[ctx.buf_ptr] = 0x80
ctx.buf_ptr += 1
}
if ctx.buf_ptr > ctx.statesize - 8 {
for ctx.buf_ptr < ctx.statesize {
ctx.buffer[ctx.buf_ptr] = 0
ctx.buf_ptr += 1
}
transform(ctx, ctx.buffer[:], u32(ctx.statesize))
ctx.buf_ptr = 0
}
for ctx.buf_ptr < ctx.statesize - 8 {
ctx.buffer[ctx.buf_ptr] = 0
ctx.buf_ptr += 1
}
ctx.block_counter += 1
ctx.buf_ptr = ctx.statesize
for ctx.buf_ptr > ctx.statesize - 8 {
ctx.buf_ptr -= 1
ctx.buffer[ctx.buf_ptr] = byte(ctx.block_counter)
ctx.block_counter >>= 8
}
transform(ctx, ctx.buffer[:], u32(ctx.statesize))
output_transformation(ctx)
for i, j := ctx.statesize - hashbytelen , 0; i < ctx.statesize; i, j = i + 1, j + 1 {
hash[j] = ctx.chaining[i % 8][i / 8]
}
}
/*
GROESTL implementation
*/
SBOX := [256]byte {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
}
SHIFT := [2][2][8]int {
{{0, 1, 2, 3, 4, 5, 6, 7}, {1, 3, 5, 7, 0, 2, 4, 6}},
{{0, 1, 2, 3, 4, 5, 6, 11}, {1, 3, 5, 11, 0, 2, 4, 6}},
}
Groestl_Context :: struct {
chaining: [8][16]byte,
block_counter: u64,
hashbitlen: int,
buffer: [128]byte,
buf_ptr: int,
bits_in_last_byte: int,
columns: int,
rounds: int,
statesize: int,
}
Groestl_Variant :: enum {
P512 = 0,
Q512 = 1,
P1024 = 2,
Q1024 = 3,
}
MUL2 :: #force_inline proc "contextless"(b: byte) -> byte {
return (b >> 7) != 0 ? (b << 1) ~ 0x1b : (b << 1)
}
MUL3 :: #force_inline proc "contextless"(b: byte) -> byte {
return MUL2(b) ~ b
}
MUL4 :: #force_inline proc "contextless"(b: byte) -> byte {
return MUL2(MUL2(b))
}
MUL5 :: #force_inline proc "contextless"(b: byte) -> byte {
return MUL4(b) ~ b
}
MUL6 :: #force_inline proc "contextless"(b: byte) -> byte {
return MUL4(b) ~ MUL2(b)
}
MUL7 :: #force_inline proc "contextless"(b: byte) -> byte {
return MUL4(b) ~ MUL2(b) ~ b
}
sub_bytes :: #force_inline proc (x: [][16]byte, columns: int) {
for i := 0; i < 8; i += 1 {
for j := 0; j < columns; j += 1 {
x[i][j] = SBOX[x[i][j]]
}
}
}
shift_bytes :: #force_inline proc (x: [][16]byte, columns: int, v: Groestl_Variant) {
temp: [16]byte
R := &SHIFT[int(v) / 2][int(v) & 1]
for i := 0; i < 8; i += 1 {
for j := 0; j < columns; j += 1 {
temp[j] = x[i][(j + R[i]) % columns]
}
for j := 0; j < columns; j += 1 {
x[i][j] = temp[j]
}
}
}
mix_bytes :: #force_inline proc (x: [][16]byte, columns: int) {
temp: [8]byte
for i := 0; i < columns; i += 1 {
for j := 0; j < 8; j += 1 {
temp[j] = MUL2(x[(j + 0) % 8][i]) ~
MUL2(x[(j + 1) % 8][i]) ~
MUL3(x[(j + 2) % 8][i]) ~
MUL4(x[(j + 3) % 8][i]) ~
MUL5(x[(j + 4) % 8][i]) ~
MUL3(x[(j + 5) % 8][i]) ~
MUL5(x[(j + 6) % 8][i]) ~
MUL7(x[(j + 7) % 8][i])
}
for j := 0; j < 8; j += 1 {
x[j][i] = temp[j]
}
}
}
p :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) {
v := ctx.columns == 8 ? Groestl_Variant.P512 : Groestl_Variant.P1024
for i := 0; i < ctx.rounds; i += 1 {
add_roundconstant(x, ctx.columns, byte(i), v)
sub_bytes(x, ctx.columns)
shift_bytes(x, ctx.columns, v)
mix_bytes(x, ctx.columns)
}
}
q :: #force_inline proc (ctx: ^Groestl_Context, x: [][16]byte) {
v := ctx.columns == 8 ? Groestl_Variant.Q512 : Groestl_Variant.Q1024
for i := 0; i < ctx.rounds; i += 1 {
add_roundconstant(x, ctx.columns, byte(i), v)
sub_bytes(x, ctx.columns)
shift_bytes(x, ctx.columns, v)
mix_bytes(x, ctx.columns)
}
}
transform :: proc(ctx: ^Groestl_Context, input: []byte, msglen: u32) {
tmp1, tmp2: [8][16]byte
input, msglen := input, msglen
for msglen >= u32(ctx.statesize) {
for i := 0; i < 8; i += 1 {
for j := 0; j < ctx.columns; j += 1 {
tmp1[i][j] = ctx.chaining[i][j] ~ input[j * 8 + i]
tmp2[i][j] = input[j * 8 + i]
}
}
p(ctx, tmp1[:])
q(ctx, tmp2[:])
for i := 0; i < 8; i += 1 {
for j := 0; j < ctx.columns; j += 1 {
ctx.chaining[i][j] ~= tmp1[i][j] ~ tmp2[i][j]
}
}
ctx.block_counter += 1
msglen -= u32(ctx.statesize)
input = input[ctx.statesize:]
}
}
output_transformation :: proc(ctx: ^Groestl_Context) {
temp: [8][16]byte
for i := 0; i < 8; i += 1 {
for j := 0; j < ctx.columns; j += 1 {
temp[i][j] = ctx.chaining[i][j]
}
}
p(ctx, temp[:])
for i := 0; i < 8; i += 1 {
for j := 0; j < ctx.columns; j += 1 {
ctx.chaining[i][j] ~= temp[i][j]
}
}
}
add_roundconstant :: proc(x: [][16]byte, columns: int, round: byte, v: Groestl_Variant) {
switch (i32(v) & 1) {
case 0:
for i := 0; i < columns; i += 1 {
x[0][i] ~= byte(i << 4) ~ round
}
case 1:
for i := 0; i < columns; i += 1 {
for j := 0; j < 7; j += 1 {
x[j][i] ~= 0xff
}
}
for i := 0; i < columns; i += 1 {
x[7][i] ~= byte(i << 4) ~ 0xff ~ round
}
}
}
File diff suppressed because it is too large Load Diff
+584
View File
@@ -0,0 +1,584 @@
package jh
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the JH hashing algorithm, as defined in <https://www3.ntu.edu.sg/home/wuhj/research/jh/index.html>
*/
import "core:os"
import "core:io"
/*
High level API
*/
DIGEST_SIZE_224 :: 28
DIGEST_SIZE_256 :: 32
DIGEST_SIZE_384 :: 48
DIGEST_SIZE_512 :: 64
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
}
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: Jh_Context
ctx.hashbitlen = 224
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
ctx: Jh_Context
ctx.hashbitlen = 224
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: Jh_Context
ctx.hashbitlen = 224
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Jh_Context
ctx.hashbitlen = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
ctx: Jh_Context
ctx.hashbitlen = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Jh_Context
ctx.hashbitlen = 256
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: Jh_Context
ctx.hashbitlen = 384
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
ctx: Jh_Context
ctx.hashbitlen = 384
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: Jh_Context
ctx.hashbitlen = 384
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: Jh_Context
ctx.hashbitlen = 512
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
ctx: Jh_Context
ctx.hashbitlen = 512
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: Jh_Context
ctx.hashbitlen = 512
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
/*
Low level API
*/
init :: proc(ctx: ^Jh_Context) {
assert(ctx.hashbitlen == 224 || ctx.hashbitlen == 256 || ctx.hashbitlen == 384 || ctx.hashbitlen == 512, "hashbitlen must be set to 224, 256, 384 or 512")
ctx.H[1] = byte(ctx.hashbitlen) & 0xff
ctx.H[0] = byte(ctx.hashbitlen >> 8) & 0xff
F8(ctx)
}
update :: proc(ctx: ^Jh_Context, data: []byte) {
databitlen := u64(len(data)) * 8
ctx.databitlen += databitlen
i := u64(0)
if (ctx.buffer_size > 0) && ((ctx.buffer_size + databitlen) < 512) {
if (databitlen & 7) == 0 {
copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)])
} else {
copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3) + 1])
}
ctx.buffer_size += databitlen
databitlen = 0
}
if (ctx.buffer_size > 0 ) && ((ctx.buffer_size + databitlen) >= 512) {
copy(ctx.buffer[ctx.buffer_size >> 3:], data[:64 - (ctx.buffer_size >> 3)])
i = 64 - (ctx.buffer_size >> 3)
databitlen = databitlen - (512 - ctx.buffer_size)
F8(ctx)
ctx.buffer_size = 0
}
for databitlen >= 512 {
copy(ctx.buffer[:], data[i:i + 64])
F8(ctx)
i += 64
databitlen -= 512
}
if databitlen > 0 {
if (databitlen & 7) == 0 {
copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3)])
} else {
copy(ctx.buffer[:], data[i:i + ((databitlen & 0x1ff) >> 3) + 1])
}
ctx.buffer_size = databitlen
}
}
final :: proc(ctx: ^Jh_Context, hash: []byte) {
if ctx.databitlen & 0x1ff == 0 {
for i := 0; i < 64; i += 1 {
ctx.buffer[i] = 0
}
ctx.buffer[0] = 0x80
ctx.buffer[63] = byte(ctx.databitlen) & 0xff
ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff
ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff
ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff
ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff
ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff
ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff
ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff
F8(ctx)
} else {
if ctx.buffer_size & 7 == 0 {
for i := (ctx.databitlen & 0x1ff) >> 3; i < 64; i += 1 {
ctx.buffer[i] = 0
}
} else {
for i := ((ctx.databitlen & 0x1ff) >> 3) + 1; i < 64; i += 1 {
ctx.buffer[i] = 0
}
}
ctx.buffer[(ctx.databitlen & 0x1ff) >> 3] |= 1 << (7 - (ctx.databitlen & 7))
F8(ctx)
for i := 0; i < 64; i += 1 {
ctx.buffer[i] = 0
}
ctx.buffer[63] = byte(ctx.databitlen) & 0xff
ctx.buffer[62] = byte(ctx.databitlen >> 8) & 0xff
ctx.buffer[61] = byte(ctx.databitlen >> 16) & 0xff
ctx.buffer[60] = byte(ctx.databitlen >> 24) & 0xff
ctx.buffer[59] = byte(ctx.databitlen >> 32) & 0xff
ctx.buffer[58] = byte(ctx.databitlen >> 40) & 0xff
ctx.buffer[57] = byte(ctx.databitlen >> 48) & 0xff
ctx.buffer[56] = byte(ctx.databitlen >> 56) & 0xff
F8(ctx)
}
switch ctx.hashbitlen {
case 224: copy(hash[:], ctx.H[100:128])
case 256: copy(hash[:], ctx.H[96:128])
case 384: copy(hash[:], ctx.H[80:128])
case 512: copy(hash[:], ctx.H[64:128])
}
}
/*
JH implementation
*/
ROUNDCONSTANT_ZERO := [64]byte {
0x6, 0xa, 0x0, 0x9, 0xe, 0x6, 0x6, 0x7,
0xf, 0x3, 0xb, 0xc, 0xc, 0x9, 0x0, 0x8,
0xb, 0x2, 0xf, 0xb, 0x1, 0x3, 0x6, 0x6,
0xe, 0xa, 0x9, 0x5, 0x7, 0xd, 0x3, 0xe,
0x3, 0xa, 0xd, 0xe, 0xc, 0x1, 0x7, 0x5,
0x1, 0x2, 0x7, 0x7, 0x5, 0x0, 0x9, 0x9,
0xd, 0xa, 0x2, 0xf, 0x5, 0x9, 0x0, 0xb,
0x0, 0x6, 0x6, 0x7, 0x3, 0x2, 0x2, 0xa,
}
SBOX := [2][16]byte {
{9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14},
{3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8},
}
Jh_Context :: struct {
hashbitlen: int,
databitlen: u64,
buffer_size: u64,
H: [128]byte,
A: [256]byte,
roundconstant: [64]byte,
buffer: [64]byte,
}
E8_finaldegroup :: proc(ctx: ^Jh_Context) {
t0,t1,t2,t3: byte
tem: [256]byte
for i := 0; i < 128; i += 1 {
tem[i] = ctx.A[i << 1]
tem[i + 128] = ctx.A[(i << 1) + 1]
}
for i := 0; i < 128; i += 1 {
ctx.H[i] = 0
}
for i := 0; i < 256; i += 1 {
t0 = (tem[i] >> 3) & 1
t1 = (tem[i] >> 2) & 1
t2 = (tem[i] >> 1) & 1
t3 = (tem[i] >> 0) & 1
ctx.H[uint(i) >> 3] |= t0 << (7 - (uint(i) & 7))
ctx.H[(uint(i) + 256) >> 3] |= t1 << (7 - (uint(i) & 7))
ctx.H[(uint(i) + 512) >> 3] |= t2 << (7 - (uint(i) & 7))
ctx.H[(uint(i) + 768) >> 3] |= t3 << (7 - (uint(i) & 7))
}
}
update_roundconstant :: proc(ctx: ^Jh_Context) {
tem: [64]byte
t: byte
for i := 0; i < 64; i += 1 {
tem[i] = SBOX[0][ctx.roundconstant[i]]
}
for i := 0; i < 64; i += 2 {
tem[i + 1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf
tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf
}
for i := 0; i < 64; i += 4 {
t = tem[i + 2]
tem[i + 2] = tem[i + 3]
tem[i + 3] = t
}
for i := 0; i < 32; i += 1 {
ctx.roundconstant[i] = tem[i << 1]
ctx.roundconstant[i + 32] = tem[(i << 1) + 1]
}
for i := 32; i < 64; i += 2 {
t = ctx.roundconstant[i]
ctx.roundconstant[i] = ctx.roundconstant[i + 1]
ctx.roundconstant[i + 1] = t
}
}
R8 :: proc(ctx: ^Jh_Context) {
t: byte
tem, roundconstant_expanded: [256]byte
for i := u32(0); i < 256; i += 1 {
roundconstant_expanded[i] = (ctx.roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1
}
for i := 0; i < 256; i += 1 {
tem[i] = SBOX[roundconstant_expanded[i]][ctx.A[i]]
}
for i := 0; i < 256; i += 2 {
tem[i+1] ~= ((tem[i] << 1) ~ (tem[i] >> 3) ~ ((tem[i] >> 2) & 2)) & 0xf
tem[i] ~= ((tem[i + 1] << 1) ~ (tem[i + 1] >> 3) ~ ((tem[i + 1] >> 2) & 2)) & 0xf
}
for i := 0; i < 256; i += 4 {
t = tem[i + 2]
tem[i+2] = tem[i + 3]
tem[i+3] = t
}
for i := 0; i < 128; i += 1 {
ctx.A[i] = tem[i << 1]
ctx.A[i + 128] = tem[(i << 1) + 1]
}
for i := 128; i < 256; i += 2 {
t = ctx.A[i]
ctx.A[i] = ctx.A[i + 1]
ctx.A[i + 1] = t
}
}
E8_initialgroup :: proc(ctx: ^Jh_Context) {
t0, t1, t2, t3: byte
tem: [256]byte
for i := u32(0); i < 256; i += 1 {
t0 = (ctx.H[i >> 3] >> (7 - (i & 7))) & 1
t1 = (ctx.H[(i + 256) >> 3] >> (7 - (i & 7))) & 1
t2 = (ctx.H[(i + 512) >> 3] >> (7 - (i & 7))) & 1
t3 = (ctx.H[(i + 768) >> 3] >> (7 - (i & 7))) & 1
tem[i] = (t0 << 3) | (t1 << 2) | (t2 << 1) | (t3 << 0)
}
for i := 0; i < 128; i += 1 {
ctx.A[i << 1] = tem[i]
ctx.A[(i << 1) + 1] = tem[i + 128]
}
}
E8 :: proc(ctx: ^Jh_Context) {
for i := 0; i < 64; i += 1 {
ctx.roundconstant[i] = ROUNDCONSTANT_ZERO[i]
}
E8_initialgroup(ctx)
for i := 0; i < 42; i += 1 {
R8(ctx)
update_roundconstant(ctx)
}
E8_finaldegroup(ctx)
}
F8 :: proc(ctx: ^Jh_Context) {
for i := 0; i < 64; i += 1 {
ctx.H[i] ~= ctx.buffer[i]
}
E8(ctx)
for i := 0; i < 64; i += 1 {
ctx.H[i + 64] ~= ctx.buffer[i]
}
}
+374
View File
@@ -0,0 +1,374 @@
package keccak
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the Keccak hashing algorithm.
This is done because the padding in the SHA3 standard was changed by the NIST, resulting in a different output.
*/
import "core:os"
import "core:io"
import "../_sha3"
/*
High level API
*/
DIGEST_SIZE_224 :: 28
DIGEST_SIZE_256 :: 32
DIGEST_SIZE_384 :: 48
DIGEST_SIZE_512 :: 64
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
}
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_224
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size")
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_224
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_224
ctx.is_keccak = true
_sha3.init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
_sha3.update(&ctx, buf[:read])
}
}
_sha3.final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_256
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size")
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_256
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_256
ctx.is_keccak = true
_sha3.init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
_sha3.update(&ctx, buf[:read])
}
}
_sha3.final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_384
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size")
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_384
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_384
ctx.is_keccak = true
_sha3.init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
_sha3.update(&ctx, buf[:read])
}
}
_sha3.final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_512
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size")
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_512
ctx.is_keccak = true
_sha3.init(&ctx)
_sha3.update(&ctx, data)
_sha3.final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: _sha3.Sha3_Context
ctx.mdlen = DIGEST_SIZE_512
ctx.is_keccak = true
_sha3.init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
_sha3.update(&ctx, buf[:read])
}
}
_sha3.final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
/*
Low level API
*/
Keccak_Context :: _sha3.Sha3_Context
init :: proc(ctx: ^_sha3.Sha3_Context) {
ctx.is_keccak = true
_sha3.init(ctx)
}
update :: proc "contextless" (ctx: ^_sha3.Sha3_Context, data: []byte) {
_sha3.update(ctx, data)
}
final :: proc "contextless" (ctx: ^_sha3.Sha3_Context, hash: []byte) {
_sha3.final(ctx, hash)
}
+182
View File
@@ -0,0 +1,182 @@
package md2
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the MD2 hashing algorithm, as defined in RFC 1319 <https://datatracker.ietf.org/doc/html/rfc1319>
*/
import "core:os"
import "core:io"
/*
High level API
*/
DIGEST_SIZE :: 16
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Md2_Context
// init(&ctx) No-op
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
ctx: Md2_Context
// init(&ctx) No-op
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Md2_Context
// init(&ctx) No-op
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
@(warning="Init is a no-op for MD2")
init :: proc(ctx: ^Md2_Context) {
// No action needed here
}
update :: proc(ctx: ^Md2_Context, data: []byte) {
for i := 0; i < len(data); i += 1 {
ctx.data[ctx.datalen] = data[i]
ctx.datalen += 1
if (ctx.datalen == DIGEST_SIZE) {
transform(ctx, ctx.data[:])
ctx.datalen = 0
}
}
}
final :: proc(ctx: ^Md2_Context, hash: []byte) {
to_pad := byte(DIGEST_SIZE - ctx.datalen)
for ctx.datalen < DIGEST_SIZE {
ctx.data[ctx.datalen] = to_pad
ctx.datalen += 1
}
transform(ctx, ctx.data[:])
transform(ctx, ctx.checksum[:])
for i := 0; i < DIGEST_SIZE; i += 1 {
hash[i] = ctx.state[i]
}
}
/*
MD2 implementation
*/
Md2_Context :: struct {
data: [DIGEST_SIZE]byte,
state: [DIGEST_SIZE * 3]byte,
checksum: [DIGEST_SIZE]byte,
datalen: int,
}
PI_TABLE := [?]byte {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76,
130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142,
187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16,
137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62,
204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215,
94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182,
118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135,
32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176,
185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221,
81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110,
133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55,
200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136,
149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242,
239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131,
20,
}
transform :: proc(ctx: ^Md2_Context, data: []byte) {
j,k,t: byte
for j = 0; j < DIGEST_SIZE; j += 1 {
ctx.state[j + DIGEST_SIZE] = data[j]
ctx.state[j + DIGEST_SIZE * 2] = (ctx.state[j + DIGEST_SIZE] ~ ctx.state[j])
}
t = 0
for j = 0; j < DIGEST_SIZE + 2; j += 1 {
for k = 0; k < DIGEST_SIZE * 3; k += 1 {
ctx.state[k] ~= PI_TABLE[t]
t = ctx.state[k]
}
t = (t + j) & 0xff
}
t = ctx.checksum[DIGEST_SIZE - 1]
for j = 0; j < DIGEST_SIZE; j += 1 {
ctx.checksum[j] ~= PI_TABLE[data[j] ~ t]
t = ctx.checksum[j]
}
}
+263
View File
@@ -0,0 +1,263 @@
package md4
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Jeroen van Rijn: Context design to be able to change from Odin implementation to bindings.
Implementation of the MD4 hashing algorithm, as defined in RFC 1320 <https://datatracker.ietf.org/doc/html/rfc1320>
*/
import "core:mem"
import "core:os"
import "core:io"
import "../util"
/*
High level API
*/
DIGEST_SIZE :: 16
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Md4_Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
ctx: Md4_Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Md4_Context
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
init :: proc(ctx: ^Md4_Context) {
ctx.state[0] = 0x67452301
ctx.state[1] = 0xefcdab89
ctx.state[2] = 0x98badcfe
ctx.state[3] = 0x10325476
}
update :: proc(ctx: ^Md4_Context, data: []byte) {
for i := 0; i < len(data); i += 1 {
ctx.data[ctx.datalen] = data[i]
ctx.datalen += 1
if(ctx.datalen == BLOCK_SIZE) {
transform(ctx, ctx.data[:])
ctx.bitlen += 512
ctx.datalen = 0
}
}
}
final :: proc(ctx: ^Md4_Context, hash: []byte) {
i := ctx.datalen
if ctx.datalen < 56 {
ctx.data[i] = 0x80
i += 1
for i < 56 {
ctx.data[i] = 0x00
i += 1
}
} else if ctx.datalen >= 56 {
ctx.data[i] = 0x80
i += 1
for i < BLOCK_SIZE {
ctx.data[i] = 0x00
i += 1
}
transform(ctx, ctx.data[:])
mem.set(&ctx.data, 0, 56)
}
ctx.bitlen += u64(ctx.datalen * 8)
ctx.data[56] = byte(ctx.bitlen)
ctx.data[57] = byte(ctx.bitlen >> 8)
ctx.data[58] = byte(ctx.bitlen >> 16)
ctx.data[59] = byte(ctx.bitlen >> 24)
ctx.data[60] = byte(ctx.bitlen >> 32)
ctx.data[61] = byte(ctx.bitlen >> 40)
ctx.data[62] = byte(ctx.bitlen >> 48)
ctx.data[63] = byte(ctx.bitlen >> 56)
transform(ctx, ctx.data[:])
for i = 0; i < 4; i += 1 {
hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff
hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff
hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff
hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff
}
}
/*
MD4 implementation
*/
BLOCK_SIZE :: 64
Md4_Context :: struct {
data: [64]byte,
state: [4]u32,
bitlen: u64,
datalen: u32,
}
/*
@note(zh): F, G and H, as mentioned in the RFC, have been inlined into FF, GG
and HH respectively, instead of declaring them separately.
*/
FF :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 {
return util.ROTL32(a + ((b & c) | (~b & d)) + x, s)
}
GG :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 {
return util.ROTL32(a + ((b & c) | (b & d) | (c & d)) + x + 0x5a827999, s)
}
HH :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 {
return util.ROTL32(a + (b ~ c ~ d) + x + 0x6ed9eba1, s)
}
transform :: proc(ctx: ^Md4_Context, data: []byte) {
a, b, c, d, i, j: u32
m: [DIGEST_SIZE]u32
for i, j = 0, 0; i < DIGEST_SIZE; i += 1 {
m[i] = u32(data[j]) | (u32(data[j + 1]) << 8) | (u32(data[j + 2]) << 16) | (u32(data[j + 3]) << 24)
j += 4
}
a = ctx.state[0]
b = ctx.state[1]
c = ctx.state[2]
d = ctx.state[3]
a = FF(a, b, c, d, m[0], 3)
d = FF(d, a, b, c, m[1], 7)
c = FF(c, d, a, b, m[2], 11)
b = FF(b, c, d, a, m[3], 19)
a = FF(a, b, c, d, m[4], 3)
d = FF(d, a, b, c, m[5], 7)
c = FF(c, d, a, b, m[6], 11)
b = FF(b, c, d, a, m[7], 19)
a = FF(a, b, c, d, m[8], 3)
d = FF(d, a, b, c, m[9], 7)
c = FF(c, d, a, b, m[10], 11)
b = FF(b, c, d, a, m[11], 19)
a = FF(a, b, c, d, m[12], 3)
d = FF(d, a, b, c, m[13], 7)
c = FF(c, d, a, b, m[14], 11)
b = FF(b, c, d, a, m[15], 19)
a = GG(a, b, c, d, m[0], 3)
d = GG(d, a, b, c, m[4], 5)
c = GG(c, d, a, b, m[8], 9)
b = GG(b, c, d, a, m[12], 13)
a = GG(a, b, c, d, m[1], 3)
d = GG(d, a, b, c, m[5], 5)
c = GG(c, d, a, b, m[9], 9)
b = GG(b, c, d, a, m[13], 13)
a = GG(a, b, c, d, m[2], 3)
d = GG(d, a, b, c, m[6], 5)
c = GG(c, d, a, b, m[10], 9)
b = GG(b, c, d, a, m[14], 13)
a = GG(a, b, c, d, m[3], 3)
d = GG(d, a, b, c, m[7], 5)
c = GG(c, d, a, b, m[11], 9)
b = GG(b, c, d, a, m[15], 13)
a = HH(a, b, c, d, m[0], 3)
d = HH(d, a, b, c, m[8], 9)
c = HH(c, d, a, b, m[4], 11)
b = HH(b, c, d, a, m[12], 15)
a = HH(a, b, c, d, m[2], 3)
d = HH(d, a, b, c, m[10], 9)
c = HH(c, d, a, b, m[6], 11)
b = HH(b, c, d, a, m[14], 15)
a = HH(a, b, c, d, m[1], 3)
d = HH(d, a, b, c, m[9], 9)
c = HH(c, d, a, b, m[5], 11)
b = HH(b, c, d, a, m[13], 15)
a = HH(a, b, c, d, m[3], 3)
d = HH(d, a, b, c, m[11], 9)
c = HH(c, d, a, b, m[7], 11)
b = HH(b, c, d, a, m[15], 15)
ctx.state[0] += a
ctx.state[1] += b
ctx.state[2] += c
ctx.state[3] += d
}
+285
View File
@@ -0,0 +1,285 @@
package md5
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the MD5 hashing algorithm, as defined in RFC 1321 <https://datatracker.ietf.org/doc/html/rfc1321>
*/
import "core:mem"
import "core:os"
import "core:io"
import "../util"
/*
High level API
*/
DIGEST_SIZE :: 16
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Md5_Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
ctx: Md5_Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Md5_Context
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = s->impl_read(buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
init :: proc(ctx: ^Md5_Context) {
ctx.state[0] = 0x67452301
ctx.state[1] = 0xefcdab89
ctx.state[2] = 0x98badcfe
ctx.state[3] = 0x10325476
}
update :: proc(ctx: ^Md5_Context, data: []byte) {
for i := 0; i < len(data); i += 1 {
ctx.data[ctx.datalen] = data[i]
ctx.datalen += 1
if(ctx.datalen == BLOCK_SIZE) {
transform(ctx, ctx.data[:])
ctx.bitlen += 512
ctx.datalen = 0
}
}
}
final :: proc(ctx: ^Md5_Context, hash: []byte){
i : u32
i = ctx.datalen
if ctx.datalen < 56 {
ctx.data[i] = 0x80
i += 1
for i < 56 {
ctx.data[i] = 0x00
i += 1
}
} else if ctx.datalen >= 56 {
ctx.data[i] = 0x80
i += 1
for i < BLOCK_SIZE {
ctx.data[i] = 0x00
i += 1
}
transform(ctx, ctx.data[:])
mem.set(&ctx.data, 0, 56)
}
ctx.bitlen += u64(ctx.datalen * 8)
ctx.data[56] = byte(ctx.bitlen)
ctx.data[57] = byte(ctx.bitlen >> 8)
ctx.data[58] = byte(ctx.bitlen >> 16)
ctx.data[59] = byte(ctx.bitlen >> 24)
ctx.data[60] = byte(ctx.bitlen >> 32)
ctx.data[61] = byte(ctx.bitlen >> 40)
ctx.data[62] = byte(ctx.bitlen >> 48)
ctx.data[63] = byte(ctx.bitlen >> 56)
transform(ctx, ctx.data[:])
for i = 0; i < 4; i += 1 {
hash[i] = byte(ctx.state[0] >> (i * 8)) & 0x000000ff
hash[i + 4] = byte(ctx.state[1] >> (i * 8)) & 0x000000ff
hash[i + 8] = byte(ctx.state[2] >> (i * 8)) & 0x000000ff
hash[i + 12] = byte(ctx.state[3] >> (i * 8)) & 0x000000ff
}
}
/*
MD4 implementation
*/
BLOCK_SIZE :: 64
Md5_Context :: struct {
data: [BLOCK_SIZE]byte,
state: [4]u32,
bitlen: u64,
datalen: u32,
}
/*
@note(zh): F, G, H and I, as mentioned in the RFC, have been inlined into FF, GG, HH
and II respectively, instead of declaring them separately.
*/
FF :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
return b + util.ROTL32(a + ((b & c) | (~b & d)) + m + t, s)
}
GG :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
return b + util.ROTL32(a + ((b & d) | (c & ~d)) + m + t, s)
}
HH :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
return b + util.ROTL32(a + (b ~ c ~ d) + m + t, s)
}
II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u32 {
return b + util.ROTL32(a + (c ~ (b | ~d)) + m + t, s)
}
transform :: proc(ctx: ^Md5_Context, data: []byte) {
i, j: u32
m: [DIGEST_SIZE]u32
for i, j = 0, 0; i < DIGEST_SIZE; i+=1 {
m[i] = u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24
j += 4
}
a := ctx.state[0]
b := ctx.state[1]
c := ctx.state[2]
d := ctx.state[3]
a = FF(a, b, c, d, m[0], 7, 0xd76aa478)
d = FF(d, a, b, c, m[1], 12, 0xe8c7b756)
c = FF(c, d, a, b, m[2], 17, 0x242070db)
b = FF(b, c, d, a, m[3], 22, 0xc1bdceee)
a = FF(a, b, c, d, m[4], 7, 0xf57c0faf)
d = FF(d, a, b, c, m[5], 12, 0x4787c62a)
c = FF(c, d, a, b, m[6], 17, 0xa8304613)
b = FF(b, c, d, a, m[7], 22, 0xfd469501)
a = FF(a, b, c, d, m[8], 7, 0x698098d8)
d = FF(d, a, b, c, m[9], 12, 0x8b44f7af)
c = FF(c, d, a, b, m[10], 17, 0xffff5bb1)
b = FF(b, c, d, a, m[11], 22, 0x895cd7be)
a = FF(a, b, c, d, m[12], 7, 0x6b901122)
d = FF(d, a, b, c, m[13], 12, 0xfd987193)
c = FF(c, d, a, b, m[14], 17, 0xa679438e)
b = FF(b, c, d, a, m[15], 22, 0x49b40821)
a = GG(a, b, c, d, m[1], 5, 0xf61e2562)
d = GG(d, a, b, c, m[6], 9, 0xc040b340)
c = GG(c, d, a, b, m[11], 14, 0x265e5a51)
b = GG(b, c, d, a, m[0], 20, 0xe9b6c7aa)
a = GG(a, b, c, d, m[5], 5, 0xd62f105d)
d = GG(d, a, b, c, m[10], 9, 0x02441453)
c = GG(c, d, a, b, m[15], 14, 0xd8a1e681)
b = GG(b, c, d, a, m[4], 20, 0xe7d3fbc8)
a = GG(a, b, c, d, m[9], 5, 0x21e1cde6)
d = GG(d, a, b, c, m[14], 9, 0xc33707d6)
c = GG(c, d, a, b, m[3], 14, 0xf4d50d87)
b = GG(b, c, d, a, m[8], 20, 0x455a14ed)
a = GG(a, b, c, d, m[13], 5, 0xa9e3e905)
d = GG(d, a, b, c, m[2], 9, 0xfcefa3f8)
c = GG(c, d, a, b, m[7], 14, 0x676f02d9)
b = GG(b, c, d, a, m[12], 20, 0x8d2a4c8a)
a = HH(a, b, c, d, m[5], 4, 0xfffa3942)
d = HH(d, a, b, c, m[8], 11, 0x8771f681)
c = HH(c, d, a, b, m[11], 16, 0x6d9d6122)
b = HH(b, c, d, a, m[14], 23, 0xfde5380c)
a = HH(a, b, c, d, m[1], 4, 0xa4beea44)
d = HH(d, a, b, c, m[4], 11, 0x4bdecfa9)
c = HH(c, d, a, b, m[7], 16, 0xf6bb4b60)
b = HH(b, c, d, a, m[10], 23, 0xbebfbc70)
a = HH(a, b, c, d, m[13], 4, 0x289b7ec6)
d = HH(d, a, b, c, m[0], 11, 0xeaa127fa)
c = HH(c, d, a, b, m[3], 16, 0xd4ef3085)
b = HH(b, c, d, a, m[6], 23, 0x04881d05)
a = HH(a, b, c, d, m[9], 4, 0xd9d4d039)
d = HH(d, a, b, c, m[12], 11, 0xe6db99e5)
c = HH(c, d, a, b, m[15], 16, 0x1fa27cf8)
b = HH(b, c, d, a, m[2], 23, 0xc4ac5665)
a = II(a, b, c, d, m[0], 6, 0xf4292244)
d = II(d, a, b, c, m[7], 10, 0x432aff97)
c = II(c, d, a, b, m[14], 15, 0xab9423a7)
b = II(b, c, d, a, m[5], 21, 0xfc93a039)
a = II(a, b, c, d, m[12], 6, 0x655b59c3)
d = II(d, a, b, c, m[3], 10, 0x8f0ccc92)
c = II(c, d, a, b, m[10], 15, 0xffeff47d)
b = II(b, c, d, a, m[1], 21, 0x85845dd1)
a = II(a, b, c, d, m[8], 6, 0x6fa87e4f)
d = II(d, a, b, c, m[15], 10, 0xfe2ce6e0)
c = II(c, d, a, b, m[6], 15, 0xa3014314)
b = II(b, c, d, a, m[13], 21, 0x4e0811a1)
a = II(a, b, c, d, m[4], 6, 0xf7537e82)
d = II(d, a, b, c, m[11], 10, 0xbd3af235)
c = II(c, d, a, b, m[2], 15, 0x2ad7d2bb)
b = II(b, c, d, a, m[9], 21, 0xeb86d391)
ctx.state[0] += a
ctx.state[1] += b
ctx.state[2] += c
ctx.state[3] += d
}

Some files were not shown because too many files have changed in this diff Show More