Compare commits

..

454 Commits

Author SHA1 Message Date
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
gingerBill 8c943eb054 Make inline array arithmetic use load+extractvalue rather than getelementptr+load to give the optimizer a better hint for vectorization 2021-06-01 10:51:54 +01:00
gingerBill 446703ba75 Improves to array arithmetic on += etc assignment statements 2021-06-01 10:37:31 +01:00
gingerBill 266b5d7d85 Fix container/map.odin 2021-06-01 09:26:01 +01:00
gingerBill d90adb7a8e Fix #998 2021-05-31 21:03:50 +01:00
gingerBill 2573da12fc Fix #992 2021-05-31 20:58:28 +01:00
gingerBill bbc9c6a93c Fix #999 2021-05-31 20:56:07 +01:00
gingerBill 673134185a Fix #996 2021-05-31 20:54:09 +01:00
gingerBill 3bf00e6125 Comment on the required generate_minimum_dependency_set entities 2021-05-31 20:50:21 +01:00
gingerBill 8fd4fe25d6 Remove unneeded minimum dependencies 2021-05-31 20:44:48 +01:00
gingerBill ea1dc5373d Remove unneeded dependencies 2021-05-31 20:39:48 +01:00
gingerBill b8d6dd4eb7 Fix #1004 2021-05-31 20:38:10 +01:00
gingerBill 4d80f8598d Fix polymorphic record "too few" lacking error message 2021-05-31 20:33:14 +01:00
Jeroen van Rijn bc4591fc1e Merge pull request #1006 from jockus/master
Fix for value rather than type used for intrinsics
2021-05-31 14:23:40 +02:00
Joakim Hentula 6465fb8ec7 Fix for value rather than type used for intrinsics 2021-05-31 13:21:13 +01:00
gingerBill 46204ed7f0 Update core:runtime to use the new intrinsics 2021-05-30 13:22:15 +01:00
gingerBill 0f91ffe28f Add intrinsics.{ptr_offset, ptr_sub} 2021-05-30 13:21:56 +01:00
gingerBill 4b46d691f8 Improve logic for intrinsics.{mem_copy, mem_copy_non_overlapping, mem_zero} to use the *.inline LLVM variants when possible 2021-05-30 12:52:44 +01:00
gingerBill 599d0cf6ac Merge pull request #1005 from Kelimion/maths
Add `abs_f16` support + endian versions of maths routines.
2021-05-30 11:48:17 +01:00
Jeroen van Rijn d7dba495fd Last of the Endian float in math.odin. 2021-05-29 18:27:43 +02:00
Jeroen van Rijn c05f6b4a31 Even more Endian maths. 2021-05-29 17:52:47 +02:00
Jeroen van Rijn a0a578c72a More Endian version of maths procs. 2021-05-29 17:21:54 +02:00
Jeroen van Rijn 55fc2c00c0 Add Endian versions of math routines. 2021-05-29 16:22:47 +02:00
Jeroen van Rijn 6944e2fc04 Add abs_f16 dependency when used. 2021-05-29 15:33:11 +02:00
gingerBill c8b353b6d8 Makefile fix 2021-05-27 14:59:45 +01:00
gingerBill 6a8a31824d Minor change to Makefile 2021-05-27 14:55:12 +01:00
gingerBill 275b8d2e8a Merge pull request #925 from Kelimion/testing
Fix `core:sys/win32` tests to use `core:testing`.
2021-05-27 14:51:09 +01:00
gingerBill 8cfdd9805d Merge branch 'master' of https://github.com/odin-lang/Odin 2021-05-27 14:46:10 +01:00
gingerBill 7d304f4e8b Convert tabs to spaces for Makefile (stupid make) 2021-05-27 14:45:57 +01:00
gingerBill b65e5d5e03 Merge pull request #1003 from jockus/master
Fix deleting substring in filepath.rel
2021-05-27 13:35:46 +01:00
jockus b110153b51 Fix accidental removal of newline 2021-05-27 12:04:24 +01:00
jockus b261937233 Remove accidental core:fmt include in path/filepath 2021-05-27 12:03:37 +01:00
jockus 4455ba5b65 Merge branch 'master' of https://github.com/odin-lang/Odin 2021-05-27 12:01:28 +01:00
jockus e8aa767c8d Fix deleting substring in filepath.release 2021-05-27 12:01:13 +01:00
gingerBill bb7bd94b0a Fix comparison bug of enumerated arrays 2021-05-27 09:52:50 +01:00
gingerBill 4a886a1bc5 Disable copy elision on assignments for the time being 2021-05-25 15:43:34 +01:00
gingerBill c21c754b6f Minimize copying on getting the address of a call if required 2021-05-24 23:51:01 +01:00
gingerBill e948fcd2f1 Use intrinsics.mem_zero in runtime.mem_zero 2021-05-24 22:41:18 +01:00
gingerBill 0c46d06e63 Add intrinsics.mem_zero 2021-05-24 22:39:27 +01:00
gingerBill 44b6e7c45d Move the mem zero into a separate procedure for reuse 2021-05-24 22:32:38 +01:00
gingerBill 284a2631fd Refactoring of lbFunctionType retrieval 2021-05-24 22:16:22 +01:00
gingerBill 3f156bcb4b Refactor backend code for assignments; Refactor some statements into separate procedures 2021-05-24 22:09:21 +01:00
gingerBill d35a9e65b6 Heavily improve the copy elision logic in the backend 2021-05-24 20:57:44 +01:00
gingerBill c440296ae8 Add @(link_section=<string>) for global variables 2021-05-24 15:41:22 +01:00
gingerBill 79f115d6a7 Handle #c_vararg correctly 2021-05-24 14:46:03 +01:00
gingerBill 39eccdf6b9 Make js default to nil allocator for the time being 2021-05-23 15:17:58 +01:00
gingerBill 71cfa0c9fe Clean up organization of package runtime 2021-05-23 12:13:13 +01:00
gingerBill e82f8214e8 Add bytes.remove, bytes.remove_all, strings.remove, strings.remove_all 2021-05-23 11:46:43 +01:00
gingerBill b8f8d4c3a1 Modify ABI for the Odin calling conventions on SysV slightly 2021-05-22 11:33:08 +01:00
gingerBill 9e2eb717fe Correct newline_limit logic 2021-05-21 15:22:35 +01:00
gingerBill f0c9f82e1b Minor changes to printer to use a bit set rather than booleans for list options 2021-05-21 13:42:29 +01:00
gingerBill cc1d3a7b19 parser.check_poly_params_for_type 2021-05-21 13:07:00 +01:00
gingerBill 159daba759 Fix ast_end_token 2021-05-21 12:44:45 +01:00
gingerBill d7e85725e1 General improves to formatting for the visitor 2021-05-21 11:16:07 +01:00
gingerBill 247f4f3293 Fix ..= logic in the backend 2021-05-21 10:51:19 +01:00
gingerBill 8758afdf4e General fixes for odinfmt 2021-05-21 10:21:23 +01:00
gingerBill 362f07d7c5 Merge pull request #997 from DanielGavin/prototype-fmt
Add odin/format and odin/printer packages
2021-05-20 21:02:26 +01:00
gingerBill fe74b479c6 Begin changes to sync2 2021-05-20 21:02:05 +01:00
Daniel Gavin 44ee0f2cdc Merge branch 'master' into prototype-fmt 2021-05-20 12:15:14 +02:00
Daniel Gavin 50035f257e don't factor in the rhs length for lines that don't have Equal tokens. 2021-05-20 12:13:23 +02:00
gingerBill 92abddddc5 Be a little more correct with the temporary Ast node 2021-05-19 15:02:36 +01:00
gingerBill 4d580ed693 Keep -vet happy 2021-05-19 14:26:20 +01:00
gingerBill 9c54ed5792 Add range-based error messages to -verbose-errors
Example:
Cannot convert '(1 + 2)' to 'untyped bool' from 'untyped integer'

	x := (1 + 2) * true;
	     ^~~~~~^
2021-05-19 14:15:57 +01:00
gingerBill 5108ebf015 Replace error calls with Token to use TokenPos 2021-05-19 13:02:44 +01:00
gingerBill 86dbcb1b20 Add -verbose-errors which shows the error in the line of code 2021-05-19 12:57:30 +01:00
gingerBill 3ac934dd15 Add suggestion for unused expression on x == y
Expression is not used: 'x == 123'
	Suggestion: Did you mean to do an assignment?
	            'x = 123;'
2021-05-19 11:58:02 +01:00
gingerBill 26ce40c188 Remove @(static) for global variables 2021-05-19 11:51:48 +01:00
gingerBill b34e4a9fd1 More minor linkage changes 2021-05-19 11:46:27 +01:00
gingerBill 28561ef5f5 Minor change to internal linkage stuff 2021-05-19 11:26:05 +01:00
gingerBill 10b798456c Add soa_zip and soa_unzip to demo.odin 2021-05-19 10:55:56 +01:00
gingerBill a580cdbe7b Delete core:sync/sync2/channel* stuff (for the time being) 2021-05-19 10:50:27 +01:00
gingerBill e82e4398b6 Add intrinsics.mem_copy and intrinsics.mem_copy_non_overlapping 2021-05-19 10:50:02 +01:00
gingerBill e0225c3579 Add intrinsics.sqrt for floating-point values 2021-05-19 10:32:41 +01:00
gingerBill 8d044fd442 Minor ABI change and cleanup 2021-05-17 17:08:25 +01:00
gingerBill 6ef96d3300 Improve untyped to typed logic for aiding the backend 2021-05-16 14:44:02 +01:00
gingerBill 2e633f57a0 Add concrete type information for untyped values as procedure arguments 2021-05-16 13:00:16 +01:00
gingerBill 50369cf19c Update LICENSE year 2021-05-16 12:48:36 +01:00
gingerBill 385385364b Fix #988 2021-05-16 12:46:25 +01:00
gingerBill 9ccdc40f65 Make .Optional_Semicolons a flag for the parser 2021-05-16 12:43:35 +01:00
gingerBill df3512b112 Make core:odin use a string for the source rather than []byte 2021-05-16 12:38:27 +01:00
gingerBill ce08e832f7 Allow ..= alongside .. as a "full range" operator; Update core:odin/parser etc 2021-05-16 12:34:35 +01:00
gingerBill 24c89b3eee Minor change 2021-05-16 00:29:22 +01:00
gingerBill 85e5be03d1 Redesign os2.Error to work with the new extended union behaviour 2021-05-16 00:25:47 +01:00
gingerBill b1cfeb6c95 Add missing instruction to pass 2021-05-15 22:14:20 +01:00
gingerBill fffb83282b Add missing instructions to pass 2021-05-15 21:24:17 +01:00
gingerBill 1cf6b6679d Add custom basic dead instruction elimination pass 2021-05-15 21:10:06 +01:00
gingerBill 7886798156 Add space 2021-05-15 19:49:48 +01:00
gingerBill 0ad599675e Improve semicolon insertion rule for dummy tokens ++ and -- 2021-05-15 19:47:00 +01:00
gingerBill 5d03bc61b8 Tokenize ++ and -- as tokens but disallow them in the parser, and give better error messages for they are used as operators/statements 2021-05-15 19:34:46 +01:00
gingerBill 5e31c04a01 Disallow duplicate unary operators for +, -, and ~ 2021-05-15 19:13:34 +01:00
gingerBill 7b7081d607 Remove old dead code 2021-05-15 18:59:54 +01:00
gingerBill 5ae564cc8c Add name to aggregate result pointer to procedures 2021-05-15 18:53:52 +01:00
gingerBill 0507b9ebb7 Fix #987 2021-05-15 18:40:06 +01:00
gingerBill f7b1290fe9 Change for i in x..y {} behaviour
Adds an extra check before incrementation to prevent the possibility of overflowing of `y` is at the limit maximum size of the integer
e.g. `for i in u8(0)..255 {}` (assuming `255` is not known at compile time)
2021-05-15 18:02:06 +01:00
gingerBill b01c2e1017 Disallow slicing of constant values 2021-05-15 16:40:40 +01:00
gingerBill 63b54ce7c6 Add minor ignoring hint on type assertions to get better code generation with no optimizations enabled 2021-05-13 12:48:12 +01:00
gingerBill b8a35c658c Remove incl/excl usage from demo 2021-05-13 12:06:35 +01:00
gingerBill 465b6139d5 Temporarily fix syscall in Linux and Freebsd (eventually to be replaced with a proper implementation) 2021-05-13 12:05:23 +01:00
gingerBill b37d344eb2 Add intrinsics.type_is_variant_of 2021-05-13 12:04:51 +01:00
gingerBill d4ee1a9e19 Correct default procedure parameter logic 2021-05-13 10:07:28 +01:00
gingerBill be12f12c3c Fix #814 2021-05-13 00:57:10 +01:00
gingerBill 2e5f57d8a1 Fix #741 2021-05-13 00:44:33 +01:00
Mikkel Hjortshøj d5c3f99655 Update feature_request.md 2021-05-13 01:26:15 +02:00
Mikkel Hjortshøj 083e9e2053 Update feature_request.md 2021-05-13 01:25:37 +02:00
gingerBill c6c5af527b Fix #746 2021-05-12 23:43:16 +01:00
gingerBill 5420cc083d Implement #807 2021-05-12 23:26:21 +01:00
gingerBill c81f7b31c6 Add explicit numbers to enum AddressingMode 2021-05-12 23:22:43 +01:00
gingerBill fdd0c726bc Improve error message to "fix" #640 2021-05-12 23:12:20 +01:00
gingerBill da9cabc334 Fix #682 2021-05-12 23:02:57 +01:00
gingerBill d962cfdc6b Fix #713 2021-05-12 22:38:37 +01:00
gingerBill dfb8143149 Fix #651 2021-05-12 22:23:43 +01:00
gingerBill d2fcbf0e1d Fix #948 2021-05-12 15:00:19 +01:00
gingerBill e08f39ec28 Remove unneeded assert 2021-05-11 16:20:50 +01:00
gingerBill d353f97f91 Add byval with align, sret attributes for SysV 2021-05-11 13:30:27 +01:00
gingerBill 8144e82c6c Fix docs for -lld 2021-05-11 13:13:34 +01:00
gingerBill d0f7cf74e9 Add llvm-config version 11 check for Darwin in Makefile 2021-05-11 12:31:56 +01:00
gingerBill e1c2528d87 Remove warning on \*nix 2021-05-11 12:29:27 +01:00
gingerBill eac61fb536 Remove LLVMAddLowerConstantIntrinsicsPass 2021-05-11 12:17:48 +01:00
gingerBill 20f7e61363 Revert LLVM-C.lib 2021-05-11 12:11:59 +01:00
gingerBill 8bb6651dda Remove test call for LLVM 2021-05-11 12:08:09 +01:00
gingerBill 8ff80dec58 Minor change (in preparation for something else) to opt passes 2021-05-11 12:00:55 +01:00
gingerBill f31b09212a Improve SysV ABI 2021-05-11 12:00:27 +01:00
gingerBill 073bd3f6c9 Update LLVM-C.lib (since it was missing many required definitions missing from the official one that LLVM supplied) 2021-05-11 10:55:55 +01:00
gingerBill 9a4d942b0b Fix debug information for array types by setting the DISubrange 2021-05-10 21:29:25 +01:00
gingerBill ff6fdc7812 Correct SysV ABI for -> (f32, bool) 2021-05-10 21:16:26 +01:00
gingerBill c85c5ec38c Merge branch 'master' of https://github.com/odin-lang/Odin 2021-05-07 13:18:07 +01:00
gingerBill d70b5475eb Minor code clean up 2021-05-07 13:18:01 +01:00
gingerBill 42138d1ad5 Merge pull request #947 from Kelimion/deprecated
Mark mem.slice_ptr_to_bytes as deprecated.
2021-05-07 10:59:08 +01:00
gingerBill 47f97b8f89 Remove unused hint 2021-05-06 14:09:50 +01:00
gingerBill 902be0d09c Improve type inference system to allow &{} alongside &T{} in some cases 2021-05-06 14:06:22 +01:00
gingerBill 502ad0c10b sync2.Auto_Reset_Event; Make atomic operations names clearer 2021-05-06 14:00:01 +01:00
gingerBill 27f5aadd5a Merge branch 'master' of https://github.com/odin-lang/Odin 2021-05-06 13:59:14 +01:00
gingerBill da7a9a3584 Improve type inference rules for implicit selector expressions
New improvements:
`(.A == x)`
`a_union_containing_many_enums = .A;`
2021-05-06 13:59:05 +01:00
Jeroen van Rijn 03862d1f48 Mark mem.slice_ptr_to_bytes as deprecated.
Use byte_slice instead.

We can't make it an alias *and* mark it as deprecated, regrettably:

```odin
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte {
    return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)};
}
@(deprecated="use byte_slice")
slice_ptr_to_bytes :: byte_slice;

"mem.odin(145:1) Constant alias declarations cannot have attributes"
```
2021-05-06 13:23:17 +02:00
Jeroen van Rijn 15ce8b0454 Merge pull request #946 from Kelimion/virtual_allocator
Fix typo in core:mem alloc() comment.
2021-05-06 11:33:08 +02:00
Jeroen van Rijn 4f51d74fc2 Fix typo in core:mem alloc() comment. 2021-05-06 11:25:41 +02:00
gingerBill b6a1ec0229 Remove debug code 2021-05-05 23:34:53 +01:00
gingerBill 60685369b9 Fix typo 2021-05-05 23:34:39 +01:00
gingerBill 0f2a9e6143 Fix LLVM store point for nested types containing procedures (e.g. ^^proc()) 2021-05-05 23:00:12 +01:00
gingerBill 278de3a92f Unify AstTernaryExpr with AstTernaryIfExpr
Allow for both syntaxes `x if cond else y` and `cond ? x : y`
Removes the confusing semantics behind `?:` which could be `if` or `when` depending on the context.
2021-05-05 15:22:54 +01:00
gingerBill abdf54800e Improve ternary expression logic within parametric polymorphic parameter assignments 2021-05-05 15:14:39 +01:00
gingerBill 579b317be8 Mark external thread local globals 2021-05-05 11:47:47 +01:00
gingerBill 08360e2337 Minor cleanup 2021-05-05 10:56:19 +01:00
gingerBill f11f84964d Merge branch 'master' of https://github.com/odin-lang/Odin 2021-05-04 23:41:45 +01:00
gingerBill bb9c1d04db Fix missing newline check 2021-05-04 23:41:35 +01:00
Jeroen van Rijn f3c4d97250 Merge pull request #942 from Kelimion/grayscale-alpha-extract
Fix gray+alpha alpha extract.
2021-05-04 17:49:09 +02:00
Jeroen van Rijn afb6ebd21e Fix gray+alpha alpha extract. 2021-05-04 17:48:43 +02:00
gingerBill 6fa5eb9e1f Update README.md 2021-05-04 15:27:41 +01:00
gingerBill 94570a24c1 Move anonymous proc generation into lbGenerator 2021-05-04 00:56:29 +01:00
gingerBill 17001bf38c Nearly approach full functionality for -use-separate-modules coupled with multithreading 2021-05-04 00:45:09 +01:00
gingerBill b83e67f45f Get LLVM backend multithread for object generation with -use-separate-modules 2021-05-04 00:06:20 +01:00
gingerBill a5eea97edb Prepare to multithread object generation 2021-05-03 20:45:27 +01:00
gingerBill 866d5302fe Add [EXPERIMENTAL] warning to -user-separate-modules help message 2021-05-03 20:05:45 +01:00
gingerBill 5d70289b69 Remove test code 2021-05-03 20:03:37 +01:00
gingerBill d76ba7895b Minor fixes to -use-separate-modules 2021-05-03 19:59:17 +01:00
gingerBill dfe1dedeb1 Experimental support for -use-separate-modules 2021-05-03 19:39:36 +01:00
gingerBill d027a5f1a4 Add min_f16 and max_f16 dependencies 2021-05-03 18:48:48 +01:00
gingerBill 746e880eb5 Begin work on making LLVM backend work with multiple modules for possible faster compilation 2021-05-03 17:43:14 +01:00
gingerBill e4286d0ff9 Force zero_init in lb_add_local in certain cases 2021-05-03 15:57:35 +01:00
gingerBill 3a556eb304 Add -test-name:<string> flag to allow specific tests to be ran 2021-05-03 15:44:57 +01:00
gingerBill b44a56118e Begin cleanup for allowing for multiple LLVM modules 2021-05-03 15:26:40 +01:00
gingerBill 0d044eabac Remove non-InContext type creations 2021-05-03 15:00:50 +01:00
Jeroen van Rijn 3cf26af600 Merge pull request #941 from Kelimion/compress_error_handling
Change General_Error.OK to nil
2021-05-03 15:39:42 +02:00
Jeroen van Rijn 9a39ce6b75 Change General_Error.OK to nil 2021-05-03 15:38:43 +02:00
gingerBill 3a5245dcce Make sure builder uses the InContext version 2021-05-03 14:36:27 +01:00
Jeroen van Rijn ca0f36be42 Merge pull request #940 from Kelimion/convert_error_checks
Convert `core:compress` and `core:image` error checks to new union co…
2021-05-03 15:09:52 +02:00
Jeroen van Rijn 59b3c472ca Convert core:compress and core:image error checks to new union comparison.
No more need for `is_kind(err, Error_Value)`, just test err == Error_Value.
2021-05-03 15:08:34 +02:00
gingerBill 357f66fcee Fix typo 2021-05-03 13:45:17 +01:00
gingerBill 050f128554 Correct hashing for union #maybe 2021-05-03 13:40:36 +01:00
gingerBill 1a3784c4df Allow unions which are comparable to also be valid map keys (i.e. hashable) 2021-05-03 13:38:15 +01:00
gingerBill 518ecaf9c9 Allow unions to be comparable if all their variants are comparable 2021-05-03 13:17:16 +01:00
gingerBill 77e2e1e1d0 Add missing skip_possible_newline_for_literal calls 2021-05-03 12:02:08 +01:00
Jeroen van Rijn 448f834b28 Remove debug print in image helper. 2021-05-03 01:23:03 +02:00
Jeroen van Rijn 9212e3176a Merge pull request #939 from Kelimion/new_png_post_processing
Don't need other path for grayscale output.
2021-05-02 21:17:00 +02:00
Jeroen van Rijn 3160a6a12c Don't need other path for grayscale output. 2021-05-02 21:11:06 +02:00
Jeroen van Rijn ef7b72d14c Merge pull request #938 from Kelimion/new_png_post_processing
Add new PNG post processing options.
2021-05-02 20:39:33 +02:00
Jeroen van Rijn 7d534769d6 Add new PNG post processing options. 2021-05-02 20:38:30 +02:00
Jeroen van Rijn 0a81fcc2af Merge pull request #937 from Kelimion/core_time
datetime_to_time's ok should default to true.
2021-05-02 13:24:33 +02:00
Jeroen van Rijn 2451014b6e datetime_to_time's ok should default to true. 2021-05-02 13:23:57 +02:00
gingerBill 348d25c43a Fix parsing error for for 2021-05-02 00:11:36 +01:00
gingerBill 9854dbe889 Remove unused import 2021-05-01 23:14:14 +01:00
Jeroen van Rijn 038337fd07 Port core:sys/win32 tests to test runner. 2021-05-02 00:10:00 +02:00
gingerBill cf0bf1a7cb Add testing.fail_now 2021-05-01 23:06:14 +01:00
gingerBill 364e6c9573 Move comment 2021-05-01 22:58:13 +01:00
gingerBill 52d38ae42b Make the core:testing runner on windows run in a separate thread to handle crashes in more safe manner 2021-05-01 22:54:27 +01:00
Jeroen van Rijn 2dbdff07c5 Merge pull request #935 from Kelimion/zlib_level_0
ZLIB level 0: LEN/NLEN = i16.
2021-05-01 21:57:36 +02:00
Jeroen van Rijn 2ad8f99790 ZLIB level 0: LEN/NLEN = i16. 2021-05-01 21:56:45 +02:00
Daniel Gavin 87a1833862 fix weird behavior of nesting proc types in structs 2021-05-01 21:26:40 +02:00
Jeroen van Rijn 0a0ba95e85 Merge pull request #934 from Kelimion/paeth
Fix Paeth for bit depth < 8.
2021-05-01 20:39:40 +02:00
Jeroen van Rijn 433d742183 Fix Paeth for bit depth < 8. 2021-05-01 20:39:00 +02:00
gingerBill b845db1618 Add prototypes for intrinsics.fixed_point_* 2021-05-01 18:26:51 +01:00
gingerBill ced7700cdb Add extra check for #no_bounds_check etc being followed by a newline or empty statement 2021-05-01 17:59:30 +01:00
gingerBill 406d2ab6ba Simplify/Fix the state_flag behaviour for code generation 2021-05-01 17:42:59 +01:00
gingerBill 327116b84b Merge branch 'master' of https://github.com/odin-lang/Odin 2021-05-01 17:30:27 +01:00
gingerBill fd56b48825 Add ODIN_ROOT information 2021-05-01 17:30:22 +01:00
Jeroen van Rijn 1ef9b094b6 Merge pull request #932 from Kelimion/png_blend_test
PNG: Fix tRNS handling.
2021-05-01 18:28:23 +02:00
Jeroen van Rijn 0659a11a1a PNG: Fix tRNS handling. 2021-05-01 18:24:31 +02:00
gingerBill 956b59d48c Update old bin/README.md 2021-05-01 16:27:11 +01:00
gingerBill 97b537f800 Update intrinsics.odin for documentation 2021-05-01 16:23:50 +01:00
Jeroen van Rijn ae907bf724 Merge pull request #931 from Kelimion/png_blend_test
Fix a few more cases in which bKGD wasn't properly applied.
2021-05-01 16:05:48 +02:00
Jeroen van Rijn db1ef078ff Fix a few more cases in which bKGD wasn't properly applied. 2021-05-01 16:05:13 +02:00
Jeroen van Rijn c2603297ee Merge pull request #928 from Kelimion/png_blend_test
PNG: Fix test for when premultiplication is needed.
2021-05-01 13:25:49 +02:00
Jeroen van Rijn a02bcd3bfd PNG: Fix test for when premultiplication is needed. 2021-05-01 13:16:47 +02:00
Mikkel Hjortshøj 0e972296a4 Change non-target indentation in Makefile to spaces to fix make error 2021-04-30 22:50:14 +02:00
Mikkel Hjortshøj 5ec82623ab Remove downloading the LLVM binaries in nightly.yml 2021-04-30 22:27:09 +02:00
Mikkel Hjortshøj 47ff50a92d Remove downloading the LLVM binaries in ci.yml 2021-04-30 22:26:15 +02:00
Mikkel Hjortshøj a1558b3398 Update nightly.yml 2021-04-30 22:19:10 +02:00
gingerBill 5f617c56e1 Minor stylistic code changes to compress and image packages 2021-04-30 10:58:29 +01:00
Jeroen van Rijn 7ef30355cb Merge pull request #924 from Kelimion/core_compress
Add `compress` and `image` to core.
2021-04-30 11:33:41 +02:00
Jeroen van Rijn 06f1eaa153 Use regular allocator from png+gzip's load_from_file.
I would've used `os.stream_from_handle`, but:
- Parts of it seem to be implemented for Windows only at the moment.
- PNG's `peek_data` using that stream didn't manage to rewind and thus tried to parse the data after the header as the header.

Two things must happen:
- The `os.stream_from_handle` implementation needs to be fixed.
- PNG and GZIP's parsers need to be able to handle streams that can't rewind or seek (backward).

Those fixes are on my TODO list but are exceed the scope of this patch.
2021-04-30 09:35:43 +02:00
Jeroen van Rijn 58e023e0cf Add compress and image to core. 2021-04-30 00:21:52 +02:00
gingerBill 222bab501c Disallow unnamed polymorphic records 2021-04-29 11:00:14 +01:00
Daniel Gavin 9c6ab05981 fix tokenizer for ~= and better struct aligning 2021-04-29 00:51:24 +02:00
gingerBill bee637aef1 Update Makefile for Linux 2021-04-28 16:23:42 +01:00
gingerBill d5844dfd2a Update llvm-config checking on Linux 2021-04-28 16:07:46 +01:00
gingerBill 3751322521 Add -no-pie flag to linker on Linux 2021-04-28 15:36:29 +01:00
gingerBill 71ac145f49 Remove dead code related to old backend 2021-04-28 15:28:14 +01:00
gingerBill e50ef33c2a Fix #921 2021-04-28 12:34:16 +01:00
gingerBill 3061dd2497 Update build.bat to use wmic os get LocalDateTime /value instead of %DATE% which is not consistent across computers 2021-04-28 11:56:47 +01:00
Daniel Gavin 088f4b5039 fix out of bounds with empty struct 2021-04-28 12:53:04 +02:00
gingerBill 002184cd49 Merge pull request #920 from rasa-silva/patch-1
Fix Makefile for OSX
2021-04-28 11:20:47 +01:00
Ricardo Silva 02da4d61ae Fix Makefile for OSX 2021-04-28 11:15:05 +01:00
gingerBill 102c29575b Allow @(test) to be ran outside of *_test.odin files 2021-04-28 10:49:40 +01:00
gingerBill 24fce21d90 Add "naked" calling convention (removes prologue and epilogue) 2021-04-28 10:49:30 +01:00
gingerBill afe185ee22 Fix procedure entity finding 2021-04-27 21:08:18 +01:00
gingerBill ffffb04d85 Remove unused import 2021-04-27 17:21:52 +01:00
gingerBill 17390cd317 Implement sync2.Recursive_Mutex using WaitOnAddress and friends on Windows 2021-04-27 17:19:12 +01:00
gingerBill 7ac80544a1 Max sync2.Sema on windows be i32 for the counter internally. 2021-04-27 16:59:25 +01:00
gingerBill 96b60d8779 Reimplement sync2.Sema on windows with WaitOnAddress primitives 2021-04-27 16:56:11 +01:00
gingerBill 24f2d97c0e Make atomic compare related intrinsics optional ok 2021-04-27 16:55:39 +01:00
gingerBill f6d98d2a16 Fix Makefile for macOs 2021-04-27 13:29:14 +01:00
gingerBill ab5460e2e2 Update CI 2021-04-27 13:22:30 +01:00
gingerBill cd1658e56c Update Makefile 2021-04-27 13:14:54 +01:00
gingerBill e7e1866e50 Fix #893 2021-04-27 13:09:37 +01:00
Daniel Gavin 51b198aa56 Merge remote-tracking branch 'upstream/master' into prototype-fmt 2021-04-27 00:06:30 +02:00
gingerBill 94fd59e6f0 Make compound literals require trailing commas if followed by a newline 2021-04-26 23:05:00 +01:00
gingerBill c07ab5f9ad Change expr_level increment rules within a compound literal 2021-04-26 23:02:00 +01:00
gingerBill 06e0da97b7 Implement ODIN_ROOT #913 2021-04-26 22:56:32 +01:00
gingerBill 04535b2913 Fix constant aliasing for debug information 2021-04-26 22:36:20 +01:00
gingerBill 6667b78c12 Correct core:os/os2 mock-up 2021-04-26 22:08:15 +01:00
gingerBill 7e0c78eae7 Fix logic for \n ignoring 2021-04-26 21:39:49 +01:00
gingerBill 6d1eb473cf Correct \n ignore rules 2021-04-26 21:25:44 +01:00
gingerBill 898245431f Make -strict-style the default #871 2021-04-26 21:07:58 +01:00
gingerBill 43942a6199 Fix odin run on Windows 2021-04-26 20:54:18 +01:00
gingerBill 53c7e65c57 Merge pull request #914 from odin-lang/old-backend-removal
Removal of the Old Backend
2021-04-26 20:50:43 +01:00
gingerBill a38586420c Fix race condition with procedure aliases checking for declarations on constant aliases 2021-04-26 19:46:42 +01:00
gingerBill 1aa9c49172 Remove warning for "Redundant 'auto_cast' applied to expression" 2021-04-26 19:17:25 +01:00
gingerBill 5a88fef483 Make corrections 2021-04-26 18:07:34 +01:00
gingerBill 43b55223af Merge branch 'master' into old-backend-removal 2021-04-26 11:46:58 +01:00
gingerBill 1d628a5e3d Change how GIT_SHA is rendered in odin version 2021-04-25 22:23:47 +01:00
gingerBill af3784ebb6 Add -DODIN_VERSION_RAW to Makefile 2021-04-25 22:19:34 +01:00
gingerBill ff933ca37f Remove old shell scripts in favour of Makefile 2021-04-25 22:13:01 +01:00
gingerBill bbf79fc1d4 Add ODIN_VERSION_RAW define to build.bat 2021-04-25 22:10:52 +01:00
gingerBill 2af8e956a6 Change versioning system from v0.13.1 to dev-2021-04 2021-04-25 22:09:22 +01:00
gingerBill 9ed826f6fb Remove import "core:runtime" from core:math/bits 2021-04-25 21:51:33 +01:00
gingerBill 07f9e551c1 Revert build.bat 2021-04-25 21:38:29 +01:00
gingerBill df4404e093 Fix typo in gb_get_env 2021-04-25 21:24:33 +01:00
gingerBill 583fd89fcf Add gb_get_env 2021-04-25 21:22:15 +01:00
gingerBill 2691c394e0 Add intrinsics.count_zeros 2021-04-25 20:50:25 +01:00
gingerBill 4662bad59c Remove unused file 2021-04-25 20:31:35 +01:00
gingerBill 7086b49ae6 Rename intrinsics to count_trailing_zeros and count_leading_zeros 2021-04-25 20:26:11 +01:00
gingerBill 72aa0e6e38 Replace many foreign llvm calls with intrinsics 2021-04-25 20:22:26 +01:00
gingerBill cb2e6ea31d Remove use_llvm_api related checks and other related things 2021-04-25 20:03:05 +01:00
gingerBill 74c683e908 Remove -llvm-api from CI 2021-04-25 19:59:35 +01:00
gingerBill 6383714bff Remove old procedure ABI code 2021-04-25 19:56:46 +01:00
gingerBill a25e796b00 Delete ir.cpp and related files 2021-04-25 19:52:37 +01:00
gingerBill 833784e196 Remove old backend specific code in main 2021-04-25 19:51:57 +01:00
gingerBill 66a70b9d27 Remove the need for LLVM_BACKEND_SUPPORT 2021-04-25 19:49:29 +01:00
gingerBill cd125c0f41 Override -llvm-api to always be true 2021-04-25 19:46:48 +01:00
Daniel Gavin 87bfd31664 force all enums newlined if there is more than one line 2021-04-23 23:42:53 +02:00
Daniel Gavin 5fba548aa0 more fixes with wierd comment placements 2021-04-23 23:22:48 +02:00
Daniel Gavin aafbf5bac7 odinfmt 2021-04-23 22:55:59 +02:00
Daniel Gavin 951e940470 handle comments in stupid places 2021-04-23 21:52:27 +02:00
Daniel Gavin 3b5b845ea6 refractor 2021-04-23 16:45:55 +02:00
Daniel Gavin 3f9ad6ba09 fix proc group, struct align with internal structs 2021-04-23 16:33:11 +02:00
Daniel Gavin f10f7ebbf1 Merge remote-tracking branch 'upstream/master' into prototype-fmt 2021-04-23 10:24:05 +02:00
Daniel Gavin 40ed7e48d0 remove prints 2021-04-22 00:56:31 +02:00
Daniel Gavin ab53900c95 check comma count in enum instead 2021-04-22 00:55:25 +02:00
Daniel Gavin 43589a56b7 odinfmt on printer 2021-04-22 00:32:36 +02:00
Daniel Gavin de1838c0cb align not mutable correctly 2021-04-22 00:23:17 +02:00
Daniel Gavin 9b8563dfc0 style 2021-04-22 00:08:03 +02:00
Daniel Gavin b18e8898d8 ran odinfmt on source 2021-04-22 00:07:07 +02:00
Daniel Gavin ca112c0b6d better placing of the end brace 2021-04-22 00:04:01 +02:00
Daniel Gavin 6eb64f2bdc align enum 2021-04-21 23:40:08 +02:00
Daniel Gavin 25c3b6dc95 align value decls 2021-04-21 23:21:45 +02:00
Daniel Gavin 3464784e5e add proc to format multiline 2021-04-19 19:41:53 +02:00
Daniel Gavin f1dc7c0b27 more work 2021-04-19 19:38:08 +02:00
Daniel Gavin c708f649ec Merge remote-tracking branch 'upstream/master' into prototype-fmt 2021-04-19 02:13:29 +02:00
Daniel Gavin f7b8b3a340 ensure that the comments gets pushed if it's in the beginning before package 2021-04-18 22:06:32 +02:00
Daniel Gavin 2cbb3443d3 ran odinfmt 2021-04-18 21:53:52 +02:00
Daniel Gavin 11bd518f36 fix bugs 2021-04-18 21:52:00 +02:00
Daniel Gavin a721802337 fixing calls in calls 2021-04-18 21:07:58 +02:00
Daniel Gavin 5a8c7b4f90 support multiline for and if 2021-04-16 02:15:29 +02:00
Daniel Gavin f17fc05ff2 format call and binary expression 2021-04-16 00:44:16 +02:00
Daniel Gavin a12db382e0 damn, ran the odinfmt with spaces instead of tabs... 2021-04-15 00:24:00 +02:00
Daniel Gavin 22daa50374 ran the odinfmt - looks good, except for multi line binary operations 2021-04-15 00:19:13 +02:00
Daniel Gavin a09300fb0e more fixes 2021-04-15 00:11:10 +02:00
Daniel Gavin bab4e5531a remove print 2021-04-14 21:53:11 +02:00
Daniel Gavin 1de928df78 fixed bug in parser on when 2021-04-14 18:43:04 +02:00
Daniel Gavin aded272b33 split stmts 2021-04-14 18:04:48 +02:00
Daniel Gavin b0721f1e0c aligning structs now work 2021-04-14 16:31:31 +02:00
Daniel Gavin 7e90ece84a more switch alignment work 2021-04-14 16:03:36 +02:00
Daniel Gavin 1f563f2810 work on switch alignment 2021-04-14 15:34:50 +02:00
Daniel Gavin c46317c00b fix os error 2021-04-14 02:20:05 +02:00
Daniel Gavin cb4b7efd3e only align comments in same indentation blocks 2021-04-14 01:57:42 +02:00
Daniel Gavin 411beaa3bf work on comments 2021-04-14 01:15:46 +02:00
Daniel Gavin 1cb3a31f32 have to sort attributes because they are not ordered by position(maybe bug on parser) 2021-04-14 00:53:34 +02:00
Daniel Gavin c99afd04ad work 2021-04-14 00:08:09 +02:00
Daniel Gavin 3157467e4b bring over the odinfmt code 2021-04-13 23:59:40 +02:00
Daniel Gavin 2001384ae6 make sure to print comments at the end of the file 2021-04-13 23:52:23 +02:00
Daniel Gavin b09e53d7fe now aligning comments 2021-04-13 23:42:58 +02:00
Daniel Gavin d046c9c072 at the same point as the previous formatter now 2021-04-13 20:18:50 +02:00
Daniel Gavin 2e8da35851 multiline comments work 2021-04-13 15:27:04 +02:00
Daniel Gavin 1d3458cadb single line comments work 2021-04-12 22:35:26 +02:00
Daniel Gavin 9139ca4673 more work on fmt 2021-04-12 17:01:43 +02:00
Daniel Gavin e0e6bba865 start new prototype 2021-04-11 19:47:33 +02:00
163 changed files with 16898 additions and 24496 deletions
@@ -7,6 +7,8 @@ assignees: ''
---
# PLEASE POST THIS IN THE DISCUSSION TAB UNDER "PROPOSALS" OR "IDEAS/REQUESTS"
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+8 -13
View File
@@ -10,12 +10,12 @@ jobs:
run: sudo apt-get install llvm-11 clang-11 llvm
- name: build odin
run: make release
- name: Odin run -llvm-api
run: ./odin run examples/demo/demo.odin -llvm-api
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Odin check
run: ./odin check examples/demo/demo.odin -vet
- name: Odin version
run: ./odin version
build_macOS:
runs-on: macos-latest
steps:
@@ -23,28 +23,21 @@ jobs:
- name: Download LLVM and setup PATH
run: |
brew install llvm@11
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
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
./odin run examples/demo/demo.odin -llvm-api
run: ./odin run examples/demo/demo.odin
- name: Odin check
run: ./odin check examples/demo/demo.odin -vet
- name: Odin version
run: ./odin version
build_windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Download and unpack LLVM bins
shell: powershell
run: |
cd bin
$ProgressPreference = "SilentlyContinue";
Invoke-WebRequest -Uri https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip -OutFile llvm-binaries.zip
7z x llvm-binaries.zip > $null
- name: build Odin
shell: cmd
run: |
@@ -60,5 +53,7 @@ jobs:
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
+2 -15
View File
@@ -10,15 +10,6 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Install cURL
run: choco install curl
- name: Download and unpack LLVM bins
shell: cmd
run: |
cd bin
curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip
7z x llvm-binaries.zip > nul
rm -f llvm-binaries.zip
- name: build Odin
shell: cmd
run: |
@@ -52,8 +43,6 @@ jobs:
run: sudo apt-get install llvm-11 clang-11 llvm
- name: build odin
run: make nightly
- name: Odin run -llvm-api
run: ./odin run examples/demo/demo.odin -llvm-api
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Copy artifacts
@@ -74,14 +63,12 @@ jobs:
- uses: actions/checkout@v1
- name: Download LLVM and setup PATH
run: |
brew install llvm
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
brew install llvm@11
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 nightly
- name: Odin run -llvm-api
run: ./odin run examples/demo/demo.odin -llvm-api
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Copy artifacts
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016-2020 Ginger Bill. All rights reserved.
Copyright (c) 2016-2021 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:
+24 -5
View File
@@ -2,18 +2,37 @@ 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)
LDFLAGS:=$(LDFLAGS) -liconv
CFLAGS:=$(CFLAGS) $(shell llvm-config --cxxflags --ldflags) -DLLVM_BACKEND_SUPPORT -DUSE_NEW_LLVM_ABI_SYSTEM
LDFLAGS:=$(LDFLAGS) -lLLVM-C
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)
CFLAGS:=$(CFLAGS) $(shell llvm-config-11 --cxxflags --ldflags) -DLLVM_BACKEND_SUPPORT -DUSE_NEW_LLVM_ABI_SYSTEM
LDFLAGS:=$(LDFLAGS) $(shell llvm-config-11 --libs core native --system-libs)
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
-2
View File
@@ -100,7 +100,6 @@ In addition, the following platform-specific steps are necessary:
- Windows
* Have Visual Studio installed (MSVC 2010 or later, for the linker)
* Have a copy of `opt.exe` and `llc.exe` in `Odin/bin`. Pre-built Windows binaries can be found [here](https://github.com/odin-lang/Odin/releases/tag/llvm-windows) and *must* be explicitly copied
* 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
@@ -128,7 +127,6 @@ Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#g
- Windows
* x86-64/amd64
* MSVC 2010 installed (C++11 support)
* [LLVM binaries](https://github.com/odin-lang/Odin/releases/tag/llvm-windows) for `opt.exe`, `llc.exe`, and `lld-link.exe`
* Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path
+3 -4
View File
@@ -2,13 +2,12 @@
## Setup
Odin only supports x86-64 at the moment (64-bit), relies on LLVM for code generation and an external linker.
Odin currently supports x86-64 and ARM64 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)
* Have a copy of `opt.exe` and `llc.exe` in `Odin/bin`. Pre-built Windows binaries can be found [here](https://github.com/odin-lang/Odin/releases/tag/llvm-windows) and *must* be explicitly copied
* 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
@@ -19,12 +18,12 @@ In addition, the following platform-specific steps are necessary:
* 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`.
**Notes for \*Nix Systems:**: The compiler currently relies on the `core` and `shared` library collection being relative to the compiler executable, by default. 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 either simply explicitly invoke the compiler with `/path/to/odin` in your preferred build system, or `set ODIN_ROOT=/path/to/odin_root`.
Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#getting-started-with-odin) for more information.
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env bash
release_mode=$1
warnings_to_disable="-std=c++11 -Wno-switch"
libraries="-pthread -ldl -lm -lstdc++ -lz -lcurses -lxml2"
other_args="-DLLVM_BACKEND_SUPPORT"
compiler="clang"
if [ -z "$release_mode" ]; then release_mode="0"; fi
if [ "$release_mode" -eq "0" ]; then
other_args="${other_args} -g"
fi
if [ "$release_mode" -eq "1" ]; then
other_args="${other_args} -O3 -march=native"
fi
if [[ "$(uname)" == "Darwin" ]]; then
# Set compiler to clang on MacOS
# MacOS provides a symlink to clang called gcc, but it's nice to be explicit here.
compiler="clang"
llvm_config_flags="--cxxflags --ldflags"
# llvm_config_flags="${llvm_config_flags} --link-static"
llvm_config="llvm-config ${llvm_config_flags}"
other_args="${other_args} -liconv"
other_args="${other_args} `${llvm_config}` -lLLVM-C"
elif [[ "$(uname)" == "FreeBSD" ]]; then
compiler="clang"
fi
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
# && ./odin run examples/demo/demo.odin -llvm-api
+12 -1
View File
@@ -1,5 +1,14 @@
@echo off
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_year=%CURR_DATE_TIME:~0,4%
set curr_month=%CURR_DATE_TIME:~4,2%
:: Make sure this is a decent name and not generic
set exe_name=odin.exe
@@ -19,8 +28,10 @@ if "%2" == "1" (
set nightly=0
)
set odin_version_raw="dev-%curr_year%-%curr_month%"
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
set compiler_defines= -DLLVM_BACKEND_SUPPORT -DUSE_NEW_LLVM_ABI_SYSTEM
set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\"
for /f %%i in ('git rev-parse --short HEAD') do set GIT_SHA=%%i
if %ERRORLEVEL% equ 0 set compiler_defines=%compiler_defines% -DGIT_SHA=\"%GIT_SHA%\"
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env bash
release_mode=$1
warnings_to_disable="-std=c++11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined"
libraries="-pthread -ldl -lm -lstdc++"
other_args=""
compiler="clang"
if [ -z "$release_mode" ]; then release_mode="0"; fi
if [ "$release_mode" -eq "0" ]; then
other_args="${other_args} -g"
fi
if [ "$release_mode" -eq "1" ]; then
other_args="${other_args} -O3 -march=native"
fi
if [[ "$(uname)" == "Darwin" ]]; then
# Set compiler to clang on MacOS
# MacOS provides a symlink to clang called gcc, but it's nice to be explicit here.
compiler="clang"
other_args="${other_args} -liconv"
elif [[ "$(uname)" == "FreeBSD" ]]; then
compiler="clang"
fi
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo/demo.odin
+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);
}
+8 -2
View File
@@ -17,6 +17,8 @@ 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,
}
@@ -25,7 +27,7 @@ DEFAULT_BUF_SIZE :: 4096;
@(private)
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;
@@ -71,8 +73,12 @@ _reader_read_new_chunk :: proc(b: ^Reader) -> io.Error {
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 {
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;
+340
View File
@@ -0,0 +1,340 @@
package bufio
import "core:bytes"
import "core:io"
import "core:mem"
import "core:unicode/utf8"
import "intrinsics"
// Extra errors returns by scanning procedures
Scanner_Extra_Error :: enum i32 {
Negative_Advance,
Advanced_Too_Far,
Bad_Read_Count,
Too_Long,
Too_Short,
}
Scanner_Error :: union {
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, .None:
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) {
err := err;
if err == .None {
err = nil;
}
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;
}
+8 -2
View File
@@ -15,6 +15,8 @@ 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) {
@@ -185,16 +187,20 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
return n, ferr;
}
}
if b.max_consecutive_empty_writes <= 0 {
b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS;
}
m: int;
nr := 0;
for nr < MAX_CONSECUTIVE_EMPTY_READS {
for nr < b.max_consecutive_empty_writes {
m, err = io.read(r, b.buf[b.n:]);
if m != 0 || err != nil {
break;
}
nr += 1;
}
if nr == MAX_CONSECUTIVE_EMPTY_READS {
if nr == b.max_consecutive_empty_writes {
return n, .No_Progress;
}
b.n += m;
+9 -1
View File
@@ -91,7 +91,7 @@ equal_fold :: proc(u, v: []byte) -> bool {
if tr < utf8.RUNE_SELF {
switch sr {
case 'A'..'Z':
case 'A'..='Z':
if tr == (sr+'a')-'A' {
continue loop;
}
@@ -526,6 +526,14 @@ replace :: proc(s, old, new: []byte, n: int, allocator := context.allocator) ->
return;
}
remove :: proc(s, key: []byte, n: int, allocator := context.allocator) -> (output: []byte, was_allocation: bool) {
return replace(s, key, {}, n, allocator);
}
remove_all :: proc(s, key: []byte, allocator := context.allocator) -> (output: []byte, was_allocation: bool) {
return remove(s, key, -1, allocator);
}
@(private) _ascii_space := [256]u8{'\t' = 1, '\n' = 1, '\v' = 1, '\f' = 1, '\r' = 1, ' ' = 1};
+4 -4
View File
@@ -139,18 +139,18 @@ append_token :: proc(a, b: ^Token) -> ^Token {
is_hex_digit :: proc(x: byte) -> bool {
switch x {
case '0'..'9', 'a'..'f', 'A'..'F':
case '0'..='9', 'a'..='f', 'A'..='F':
return true;
}
return false;
}
from_hex :: proc(x: byte) -> i32 {
switch x {
case '0'..'9':
case '0'..='9':
return i32(x) - '0';
case 'a'..'f':
case 'a'..='f':
return i32(x) - 'a' + 10;
case 'A'..'F':
case 'A'..='F':
return i32(x) - 'A' + 10;
}
return 16;
+4 -4
View File
@@ -5,9 +5,9 @@ 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;
}
@@ -45,7 +45,7 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool
case '"': r = '"';
case '\'': r = '\'';
case '0'..'7':
case '0'..='7':
v := int(c-'0');
if len(s) < 2 {
return;
+4 -4
View File
@@ -224,11 +224,11 @@ scan_string :: proc(t: ^Tokenizer) -> string {
digit_val :: proc(r: rune) -> int {
switch r {
case '0'..'9':
case '0'..='9':
return int(r-'0');
case 'A'..'F':
case 'A'..='F':
return int(r-'A' + 10);
case 'a'..'f':
case 'a'..='f':
return int(r-'a' + 10);
}
return 16;
@@ -245,7 +245,7 @@ scan_escape :: proc(t: ^Tokenizer) -> bool {
advance_rune(t);
return true;
case '0'..'7':
case '0'..='7':
for digit_val(t.ch) < 8 {
advance_rune(t);
}
+478
View File
@@ -0,0 +1,478 @@
package compress
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
*/
import "core:io"
import "core:image"
import "core:bytes"
/*
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 {
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,
}
General_Error :: enum {
File_Not_Found,
Cannot_Open_File,
File_Too_Short,
Stream_Too_Short,
Output_Too_Short,
Unknown_Compression_Method,
Checksum_Failed,
Incompatible_Options,
Unimplemented,
/*
Memory errors
*/
Allocation_Failed,
Resize_Failed,
}
GZIP_Error :: enum {
Invalid_GZIP_Signature,
Reserved_Flag_Set,
Invalid_Extra_Data,
Original_Name_Too_Long,
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 {
Invalid_ZIP_File_Signature,
Unexpected_Signature,
Insert_Next_Disk,
Expected_End_of_Central_Directory_Record,
}
ZLIB_Error :: enum {
Unsupported_Window_Size,
FDICT_Unsupported,
Unsupported_Compression_Level,
Code_Buffer_Malformed,
}
Deflate_Error :: enum {
Huffman_Bad_Sizes,
Huffman_Bad_Code_Lengths,
Inflate_Error,
Bad_Distance,
Bad_Huffman_Code,
Len_Nlen_Mismatch,
BType_3,
}
// 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,
/*
If we know the data size, we can optimize the reads and writes.
*/
size_packed: i64,
size_unpacked: i64,
}
#assert(size_of(Context_Memory_Input) == 64);
Context_Stream_Input :: struct #packed {
input_data: []u8,
input: io.Stream,
output: ^bytes.Buffer,
bytes_written: i64,
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.
*/
// TODO: Make these return compress.Error errors.
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;
}
}
if len(z.input_data) == 0 {
return []u8{}, .EOF;
} else {
return []u8{}, .Short_Buffer;
}
}
@(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;
}
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 := z.input->impl_seek(0, .Current);
if e1 != .None {
return T{}, e1;
}
r, e2 := io.to_reader_at(z.input);
if !e2 {
return T{}, .Empty;
}
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;
}
res = (^T)(&b[0])^;
return res, .None;
}
peek_data :: proc{peek_data_from_memory, peek_data_from_stream};
// Sliding window read back
@(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 z.output.buf[z.bytes_written - offset], .None;
}
// Generalized bit reader LSB
@(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 len(z.input_data) != 0 {
b = u64(z.input_data[0]);
z.input_data = z.input_data[1:];
} else {
b = 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 = max(u64);
return;
}
b, err := read_u8(z);
if err != .None {
// This is fine at the end of the file.
return;
}
z.code_buffer |= (u64(b) << u8(z.num_bits));
z.num_bits += 8;
}
}
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);
}
@(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);
}
return u32(z.code_buffer & ~(~u64(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));
}
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));
}
@(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));
}
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};
+89
View File
@@ -0,0 +1,89 @@
//+ignore
package gzip
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 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
TEST: []u8 = {
0x1f, 0x8b, 0x08, 0x1c, 0xcb, 0x3b, 0x3a, 0x5a,
0x02, 0x03, 0x07, 0x00, 0x61, 0x62, 0x03, 0x00,
0x63, 0x64, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x6e,
0x61, 0x6d, 0x65, 0x00, 0x54, 0x68, 0x69, 0x73,
0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f,
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{};
stdout :: proc(s: string) {
os.write_string(os.stdout, s);
}
stderr :: proc(s: string) {
os.write_string(os.stderr, s);
}
args := os.args;
if len(args) < 2 {
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: Error;
for file in args {
if file == "-" {
// Read from stdin
s := os.stream_from_handle(os.stdin);
ctx := &compress.Context_Stream_Input{
input = s,
};
err = load(ctx, &buf);
} else {
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("GZIP returned an error.\n");
bytes.buffer_destroy(&buf);
os.exit(2);
}
stdout(bytes.buffer_to_string(&buf));
}
bytes.buffer_destroy(&buf);
}
+367
View File
@@ -0,0 +1,367 @@
package gzip
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 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"
import "core:io"
import "core:bytes"
import "core:hash"
Magic :: enum u16le {
GZIP = 0x8b << 8 | 0x1f,
}
Header :: struct #packed {
magic: Magic,
compression_method: Compression,
flags: Header_Flags,
modification_time: u32le,
xfl: Compression_Flags,
os: OS,
}
#assert(size_of(Header) == 10);
Header_Flag :: enum u8 {
// Order is important
text = 0,
header_crc = 1,
extra = 2,
name = 3,
comment = 4,
reserved_1 = 5,
reserved_2 = 6,
reserved_3 = 7,
}
Header_Flags :: distinct bit_set[Header_Flag; u8];
OS :: enum u8 {
FAT = 0,
Amiga = 1,
VMS = 2,
Unix = 3,
VM_CMS = 4,
Atari_TOS = 5,
HPFS = 6,
Macintosh = 7,
Z_System = 8,
CP_M = 9,
TOPS_20 = 10,
NTFS = 11,
QDOS = 12,
Acorn_RISCOS = 13,
_Unknown = 14,
Unknown = 255,
}
OS_Name :: #partial [OS]string{
.FAT = "FAT",
.Amiga = "Amiga",
.VMS = "VMS/OpenVMS",
.Unix = "Unix",
.VM_CMS = "VM/CMS",
.Atari_TOS = "Atari TOS",
.HPFS = "HPFS",
.Macintosh = "Macintosh",
.Z_System = "Z-System",
.CP_M = "CP/M",
.TOPS_20 = "TOPS-20",
.NTFS = "NTFS",
.QDOS = "QDOS",
.Acorn_RISCOS = "Acorn RISCOS",
.Unknown = "Unknown",
};
Compression :: enum u8 {
DEFLATE = 8,
}
Compression_Flags :: enum u8 {
Maximum_Compression = 2,
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;
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le));
load :: proc{load_from_slice, load_from_file, load_from_context};
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
data, ok := os.read_entire_file(filename, allocator);
defer delete(data);
err = E_General.File_Not_Found;
if ok {
err = load_from_slice(data, buf, len(data), expected_output_size, allocator);
}
return;
}
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
buf := buf;
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) {
buf := buf;
expected_output_size := expected_output_size;
input_data_consumed := 0;
z.output = buf;
if expected_output_size > 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;
}
if header.compression_method != .DEFLATE {
return E_General.Unknown_Compression_Method;
}
if 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;
}
// printf("signature: %v\n", header.magic);
// printf("compression: %v\n", header.compression_method);
// printf("flags: %v\n", header.flags);
// printf("modification time: %v\n", time.unix(i64(header.modification_time), 0));
// printf("xfl: %v (%v)\n", header.xfl, int(header.xfl));
// printf("os: %v\n", OS_Name[header.os]);
if .extra in header.flags {
xlen, e_extra := compress.read_data(z, u16le);
input_data_consumed += 2;
if e_extra != .None {
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;
}
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(z, [2]u8);
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
}
xlen -= 2;
input_data_consumed += 2;
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;
}
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;
}
// printf(" Field \"%v\" of length %v found: ", string(field_id[:]), field_length);
if field_length > 0 {
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;
}
xlen -= field_length;
input_data_consumed += int(field_length);
// printf("%v\n", string(field_data));
}
if xlen != 0 {
return E_GZIP.Invalid_Extra_Data;
}
}
}
if .name in header.flags {
// Should be enough.
name: [1024]u8;
i := 0;
name_error: io.Error;
for i < len(name) {
b, name_error = compress.read_slice(z, 1);
if name_error != .None {
return E_General.Stream_Too_Short;
}
input_data_consumed += 1;
if b[0] == 0 {
break;
}
name[i] = b[0];
i += 1;
if i >= len(name) {
return E_GZIP.Original_Name_Too_Long;
}
}
// printf("Original filename: %v\n", string(name[:i]));
}
if .comment in header.flags {
// Should be enough.
comment: [1024]u8;
i := 0;
comment_error: io.Error;
for i < len(comment) {
b, comment_error = compress.read_slice(z, 1);
if comment_error != .None {
return E_General.Stream_Too_Short;
}
input_data_consumed += 1;
if b[0] == 0 {
break;
}
comment[i] = b[0];
i += 1;
if i >= len(comment) {
return E_GZIP.Comment_Too_Long;
}
}
// printf("Comment: %v\n", string(comment[:i]));
}
if .header_crc in header.flags {
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;
}
/*
We don't actually check the CRC16 (lower 2 bytes of CRC32 of header data until the CRC field).
If we find a gzip file in the wild that sets this field, we can add proper support for it.
*/
}
/*
We should have arrived at the ZLIB payload.
*/
payload_u32le: u32le;
// fmt.printf("known_gzip_size: %v | expected_output_size: %v\n", known_gzip_size, expected_output_size);
if expected_output_size > -1 {
/*
We already checked that it's not larger than the output buffer max,
or GZIP length field's max.
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(z);
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;
payload := bytes.buffer_to_bytes(buf);
crc32 := u32le(hash.crc32(payload));
if crc32 != payload_crc {
return E_GZIP.Payload_CRC_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);
}
payload_len := transmute(u32le)payload_len_b;
if len(payload) != int(payload_len) {
return E_GZIP.Payload_Length_Invalid;
}
return nil;
}
+52
View File
@@ -0,0 +1,52 @@
//+ignore
package zlib
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 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,
};
OUTPUT_SIZE :: 438;
buf: bytes.Buffer;
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
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);
}
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);
}
+715
View File
@@ -0,0 +1,715 @@
package zlib
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 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:hash"
import "core:bytes"
/*
zlib.inflate decompresses a ZLIB stream passed in as a []u8 or io.Stream.
Returns: Error.
*/
/*
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,
Reserved = 15,
}
Compression_Level :: enum u8 {
Fastest = 0,
Fast = 1,
Default = 2,
Maximum = 3,
}
Options :: struct {
window_size: u16,
level: u8,
}
Error :: compress.Error;
E_General :: compress.General_Error;
E_ZLIB :: compress.ZLIB_Error;
E_Deflate :: compress.Deflate_Error;
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);
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,
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,
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,
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,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 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, 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);
/*
ZLIB-style Huffman encoding.
JPEG packs from left, ZLIB from right. We can't share code.
*/
Huffman_Table :: struct {
fast: [1 << ZFAST_BITS]u16,
firstcode: [16]u16,
maxcode: [17]int,
firstsymbol: [16]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);
// 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 >>= (16 - bits);
return;
}
@(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;
}
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) {
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;
k := int(0);
mem.zero_slice(sizes[:]);
mem.zero_slice(z.fast[:]);
for v in code_lengths {
sizes[v] += 1;
}
sizes[0] = 0;
for i in 1..<(HUFFMAN_MAX_BITS+1) {
if sizes[i] > (1 << uint(i)) {
return E_Deflate.Huffman_Bad_Sizes;
}
}
code := int(0);
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;
}
}
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i));
code <<= 1;
k += int(sizes[i]);
}
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);
for j < (1 << ZFAST_BITS) {
z.fast[j] = fastv;
j += (1 << v);
}
}
next_code[v] += 1;
}
}
return nil;
}
@(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));
k := int(z_bit_reverse(code, 16));
s: u8;
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
if k < t.maxcode[s] {
break;
}
s += 1;
}
if s >= 16 {
return 0, E_Deflate.Bad_Huffman_Code;
}
// code size is s, so:
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;
}
if t.size[b] != s {
return 0, E_Deflate.Bad_Huffman_Code;
}
compress.consume_bits_lsb(z, s);
r = t.value[b];
return r, nil;
}
@(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 > 63 {
return 0, E_ZLIB.Code_Buffer_Malformed;
}
compress.refill_lsb(z);
if z.num_bits > 63 {
return 0, E_General.Stream_Too_Short;
}
}
#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;
}
return decode_huffman_slowpath(z, t);
}
@(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);
if e != nil {
return err;
}
if value < 256 {
e := write_byte(z, u8(value));
if e != .None {
return E_General.Output_Too_Short;
}
} else {
if value == 256 {
// End of block
return nil;
}
value -= 257;
length := Z_LENGTH_BASE[value];
if Z_LENGTH_EXTRA[value] > 0 {
length += u16(compress.read_bits_lsb(z, Z_LENGTH_EXTRA[value]));
}
value, e = decode_huffman(z, z_offset);
if e != nil {
return E_Deflate.Bad_Huffman_Code;
}
distance := Z_DIST_BASE[value];
if Z_DIST_EXTRA[value] > 0 {
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;
}
/*
These might be sped up with a repl_byte call that copies
from the already written output more directly, and that
update the Adler checksum once after.
That way we'd suffer less Stream vtable overhead.
*/
if distance == 1 {
/*
Replicate the last outputted byte, length times.
*/
if length > 0 {
c := z.output.buf[z.bytes_written - i64(distance)];
e := repl_byte(z, length, c);
if e != .None {
return E_General.Output_Too_Short;
}
}
} else {
if length > 0 {
e := repl_bytes(z, length, distance);
if e != .None {
return E_General.Output_Too_Short;
}
}
}
}
}
}
@(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.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 {
size, size_err := compress.input_size(ctx);
if size < 6 || size_err != nil {
return E_General.Stream_Too_Short;
}
cmf, _ := compress.read_u8(ctx);
method := Compression_Method(cmf & 0xf);
if method != .DEFLATE {
return E_General.Unknown_Compression_Method;
}
cinfo := (cmf >> 4) & 0xf;
if cinfo > 7 {
return E_ZLIB.Unsupported_Window_Size;
}
flg, _ := compress.read_u8(ctx);
fcheck := flg & 0x1f;
fcheck_computed := (cmf << 8 | flg) & 0x1f;
if fcheck != fcheck_computed {
return E_General.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;
}
// flevel := Compression_Level((flg >> 6) & 3);
/*
Inflate can consume bits belonging to the Adler checksum.
We pass the entire stream to Inflate and will unget bytes if we need to
at the end to compare checksums.
*/
}
// Parse ZLIB stream without header.
err = inflate_raw(z=ctx, expected_output_size=expected_output_size);
if err != nil {
return err;
}
if !raw {
compress.discard_to_next_byte_lsb(ctx);
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 E_General.Checksum_Failed;
}
}
return nil;
}
// TODO: Check alignment of reserve/resize.
@(optimization_mode="speed")
inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check {
expected_output_size := expected_output_size;
/*
Always set up a minimum allocation size.
*/
expected_output_size = max(max(expected_output_size, compress.COMPRESS_OUTPUT_ALLOCATE_MIN), 512);
// fmt.printf("\nZLIB: Expected Payload Size: %v\n\n", expected_output_size);
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);
};
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;
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);
final := u32(0);
type := u32(0);
for {
final = compress.read_bits_lsb(z, 1);
type = compress.read_bits_lsb(z, 2);
// fmt.printf("Final: %v | Type: %v\n", final, type);
switch type {
case 0:
// Uncompressed block
// Discard bits until next byte boundary
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));
// 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;
}
/*
TODO: Maybe speed this up with a stream-to-stream copy (read_from)
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;
}
case 3:
return E_Deflate.BType_3;
case:
// log.debugf("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;
}
} else {
lencodes: [286+32+137]u8;
codelength_sizes: [19]u8;
//i: 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;
#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;
}
n = 0;
c: u16;
for n < ntot {
c, err = decode_huffman(z, codelength_ht);
if err != nil {
return err;
}
if c < 0 || c >= 19 {
return E_Deflate.Huffman_Bad_Code_Lengths;
}
if c < 16 {
lencodes[n] = u8(c);
n += 1;
} else {
fill := u8(0);
compress.refill_lsb(z, 7);
switch c {
case 16:
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3);
if n == 0 {
return E_Deflate.Huffman_Bad_Code_Lengths;
}
fill = lencodes[n - 1];
case 17:
c = u16(compress.read_bits_no_refill_lsb(z, 3) + 3);
case 18:
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11);
case:
return E_Deflate.Huffman_Bad_Code_Lengths;
}
if ntot - n < u32(c) {
return E_Deflate.Huffman_Bad_Code_Lengths;
}
nc := n + u32(c);
#no_bounds_check for ; n < nc; n += 1 {
lencodes[n] = fill;
}
}
}
if n != ntot {
return E_Deflate.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;
}
}
if final == 1 {
break;
}
}
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, expected_output_size := -1) -> (err: Error) {
ctx := compress.Context_Memory_Input{};
ctx.input_data = input;
ctx.output = buf;
err = inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size);
return err;
}
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_context, inflate_from_byte_array};
+1 -1
View File
@@ -3,7 +3,7 @@ package container
import "core:mem"
import "core:runtime"
Array :: struct(T: typeid) {
Array :: struct($T: typeid) {
data: ^T,
len: int,
cap: int,
+6 -6
View File
@@ -4,12 +4,12 @@ import "intrinsics"
_ :: intrinsics;
Map :: struct(Key, Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
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) {
Map_Entry :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
hash: uintptr,
next: int,
key: Key,
@@ -141,7 +141,7 @@ map_clear :: proc(m: ^$M/Map($Key, $Value)) {
multi_map_find_first :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Map_Entry(Value) {
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;
@@ -149,7 +149,7 @@ multi_map_find_first :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Map_Entry(Va
return array_get_ptr(m.entries, i);
}
multi_map_find_next :: proc(m: $M/Map($Key, $Value), e: ^Map_Entry(Value)) -> ^Map_Entry(Value) {
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);
@@ -220,7 +220,7 @@ multi_map_insert :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
}
}
multi_map_remove :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Value)) {
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);
@@ -306,7 +306,7 @@ _map_find_key :: proc(m: $M/Map($Key, $Value), key: Key) -> Map_Find_Result wher
return fr;
}
_map_find_entry :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Value)) -> Map_Find_Result {
_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;
+1 -1
View File
@@ -1,6 +1,6 @@
package container
Priority_Queue :: struct(T: typeid) {
Priority_Queue :: struct($T: typeid) {
data: Array(T),
len: int,
priority: proc(item: T) -> int,
+1 -1
View File
@@ -1,6 +1,6 @@
package container
Queue :: struct(T: typeid) {
Queue :: struct($T: typeid) {
data: Array(T),
len: int,
offset: int,
+1 -1
View File
@@ -1,7 +1,7 @@
package container
Ring :: struct(T: typeid) {
Ring :: struct($T: typeid) {
next, prev: ^Ring(T),
value: T,
}
+1 -1
View File
@@ -1,6 +1,6 @@
package container
Small_Array :: struct(N: int, T: typeid) where N >= 0 {
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
data: [N]T,
len: int,
}
+4 -4
View File
@@ -201,9 +201,9 @@ next_token :: proc(p: ^Parser) -> Token {
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;
}
@@ -241,7 +241,7 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool
case '"': r = '"';
case '\'': r = '\'';
case '0'..'7':
case '0'..='7':
v := int(c-'0');
if len(s) < 2 {
return;
+5 -5
View File
@@ -232,7 +232,7 @@ get_pos :: proc(t: ^Tokenizer) -> Pos {
is_letter :: proc(r: rune) -> bool {
switch r {
case 'a'..'z', 'A'..'Z', '_':
case 'a'..='z', 'A'..='Z', '_':
return true;
}
return false;
@@ -240,7 +240,7 @@ is_letter :: proc(r: rune) -> bool {
is_digit :: proc(r: rune) -> bool {
switch r {
case '0'..'9':
case '0'..='9':
return true;
}
return false;
@@ -273,9 +273,9 @@ scan_identifier :: proc(t: ^Tokenizer) -> string {
digit_value :: 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;
}
+6 -6
View File
@@ -290,9 +290,9 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
for c in s[2:4] {
x: rune;
switch c {
case '0'..'9': x = c - '0';
case 'a'..'f': x = c - 'a' + 10;
case 'A'..'F': x = c - 'A' + 10;
case '0'..='9': x = c - '0';
case 'a'..='f': x = c - 'a' + 10;
case 'A'..='F': x = c - 'A' + 10;
case: return -1;
}
r = r*16 + x;
@@ -308,9 +308,9 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
for c in s[2:6] {
x: rune;
switch c {
case '0'..'9': x = c - '0';
case 'a'..'f': x = c - 'a' + 10;
case 'A'..'F': x = c - 'A' + 10;
case '0'..='9': x = c - '0';
case 'a'..='f': x = c - 'a' + 10;
case 'A'..='F': x = c - 'A' + 10;
case: return -1;
}
r = r*16 + x;
+8 -8
View File
@@ -82,7 +82,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
for t.offset < len(t.data) {
next_rune(t);
switch t.r {
case '0'..'9', 'a'..'f', 'A'..'F':
case '0'..='9', 'a'..='f', 'A'..='F':
// Okay
case:
return;
@@ -100,7 +100,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
for i := 0; i < 4; i += 1 {
r := next_rune(t);
switch r {
case '0'..'9', 'a'..'f', 'A'..'F':
case '0'..='9', 'a'..='f', 'A'..='F':
// Okay
case:
return false;
@@ -149,7 +149,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
skip_alphanum :: proc(t: ^Tokenizer) {
for t.offset < len(t.data) {
switch next_rune(t) {
case 'A'..'Z', 'a'..'z', '0'..'9', '_':
case 'A'..='Z', 'a'..='z', '0'..='9', '_':
continue;
}
@@ -173,7 +173,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
token.kind = .EOF;
err = .EOF;
case 'A'..'Z', 'a'..'z', '_':
case 'A'..='Z', 'a'..='z', '_':
token.kind = .Ident;
skip_alphanum(t);
@@ -200,7 +200,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
case '-':
switch t.r {
case '0'..'9':
case '0'..='9':
// Okay
case:
// Illegal use of +/-
@@ -219,7 +219,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
}
fallthrough;
case '0'..'9':
case '0'..='9':
token.kind = t.parse_integers ? .Integer : .Float;
if t.spec == .JSON5 { // Hexadecimal Numbers
if curr_rune == '0' && (t.r == 'x' || t.r == 'X') {
@@ -361,7 +361,7 @@ is_valid_number :: proc(str: string, spec: Specification) -> bool {
switch s[0] {
case '0':
s = s[1:];
case '1'..'9':
case '1'..='9':
s = s[1:];
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:];
@@ -453,7 +453,7 @@ is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
for j := 0; j < 4; j += 1 {
c2 := hex[j];
switch c2 {
case '0'..'9', 'a'..'z', 'A'..'Z':
case '0'..='9', 'a'..='z', 'A'..='Z':
// Okay
case:
return false;
+3 -14
View File
@@ -641,9 +641,9 @@ fmt_write_padding :: proc(fi: ^Info, width: int) {
return;
}
pad_byte: byte = '0';
if fi.space {
pad_byte = ' ';
pad_byte: byte = ' ';
if !fi.space {
pad_byte = '0';
}
for i := 0; i < width; i += 1 {
@@ -1908,17 +1908,6 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
}
}
handle_relative_pointer :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
if ptr^ == 0 {
return nil;
}
when intrinsics.type_is_unsigned(T) {
return rawptr(uintptr(ptr) + uintptr(ptr^));
} else {
return rawptr(uintptr(ptr) + uintptr(i64(ptr^)));
}
}
}
fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
+3 -74
View File
@@ -1,86 +1,15 @@
package hash
crc32 :: proc(data: []byte, seed := u32(0)) -> u32 #no_bounds_check {
result := ~u32(seed);
for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
@(optimization_mode="speed")
crc64 :: proc(data: []byte, seed := u32(0)) -> u64 #no_bounds_check {
result := ~u64(seed);
for b in data {
#no_bounds_check for b in data {
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
}
return ~result;
}
@private _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
@private _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
+401
View File
@@ -0,0 +1,401 @@
package hash
import "intrinsics"
@(optimization_mode="speed")
crc32 :: proc(data: []byte, seed := u32(0)) -> u32 #no_bounds_check {
crc := ~seed;
buffer := raw_data(data);
length := len(data);
for length != 0 && uintptr(buffer) & 7 != 0 {
crc = crc32_table[0][byte(crc) ~ buffer^] ~ (crc >> 8);
buffer = intrinsics.ptr_offset(buffer, 1);
length -= 1;
}
for length >= 8 {
buf := (^[8]byte)(buffer);
word := u32((^u32le)(buffer)^);
crc ~= word;
crc = crc32_table[7][crc & 0xff] ~
crc32_table[6][(crc >> 8) & 0xff] ~
crc32_table[5][(crc >> 16) & 0xff] ~
crc32_table[4][(crc >> 24) & 0xff] ~
crc32_table[3][buf[4]] ~
crc32_table[2][buf[5]] ~
crc32_table[1][buf[6]] ~
crc32_table[0][buf[7]];
buffer = intrinsics.ptr_offset(buffer, 8);
length -= 8;
}
for length != 0 {
crc = crc32_table[0][byte(crc) ~ buffer^] ~ (crc >> 8);
buffer = intrinsics.ptr_offset(buffer, 1);
length -= 1;
}
return ~crc;
}
@(private)
crc32_table := [8][256]u32{
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
},
{
0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7,
0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf,
0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496,
0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e,
0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265,
0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d,
0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034,
0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c,
0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2,
0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca,
0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93,
0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b,
0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60,
0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768,
0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31,
0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539,
0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c,
0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484,
0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd,
0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5,
0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e,
0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026,
0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f,
0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277,
0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189,
0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81,
0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8,
0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0,
0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b,
0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23,
0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a,
0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72,
},
{
0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685,
0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d,
0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5,
0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d,
0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065,
0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd,
0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315,
0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad,
0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45,
0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd,
0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835,
0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d,
0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5,
0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d,
0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5,
0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d,
0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05,
0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd,
0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75,
0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd,
0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5,
0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d,
0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895,
0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d,
0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5,
0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d,
0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5,
0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d,
0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625,
0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d,
0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555,
0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed,
},
{
0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9,
0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056,
0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26,
0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9,
0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787,
0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68,
0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018,
0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7,
0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084,
0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b,
0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b,
0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4,
0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba,
0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755,
0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825,
0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca,
0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82,
0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d,
0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d,
0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2,
0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc,
0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953,
0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623,
0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc,
0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf,
0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50,
0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120,
0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf,
0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981,
0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e,
0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e,
0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1,
},
{
0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, 0xb220dc10,
0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, 0x825097d1,
0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92,
0x5090dc43, 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, 0xe2b00053,
0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314,
0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5,
0xa121b886, 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, 0x13016496,
0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57,
0x58f35849, 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459,
0x68831388, 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98,
0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, 0xf0f340bb, 0xb7533a6b, 0x8a3313db,
0x0863840a, 0x3503adba, 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a,
0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d,
0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, 0x2602c92c, 0x1b62e09c,
0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf,
0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, 0x7b82771e,
0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, 0x03c66c82,
0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743,
0xd1062710, 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, 0x6326fb00,
0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1,
0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386,
0x4057d457, 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, 0xf2770847,
0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404,
0x20b743d5, 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5,
0xe915e8db, 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb,
0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, 0x11852c6a, 0x562556ba, 0x6b457f0a,
0x89f57f59, 0xb49556e9, 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349,
0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888,
0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, 0xa794327f, 0x9af41bcf,
0x18a48c1e, 0x25c4a5ae, 0x6264df7e, 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e,
0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, 0xfa148c4d,
0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c,
},
{
0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, 0x1d0530b8,
0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, 0xf156b2d5,
0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223,
0xef8580f6, 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, 0xf280b04e,
0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e,
0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3,
0x047a07ad, 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, 0x197f3715,
0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578,
0x0f580a6c, 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4,
0xe30b8801, 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9,
0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, 0x5c439944, 0xdad7ebea, 0x118b384f,
0xe0dd8a9a, 0x2b81593f, 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22,
0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2,
0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f,
0x0b220dc1, 0xc07ede64, 0x46eaacca, 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79,
0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14,
0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, 0x03b52460,
0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d,
0x1d661643, 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, 0x006326fb,
0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496,
0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156,
0xf54f9383, 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, 0xe84aa33b,
0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd,
0xf6999118, 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0,
0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c,
0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, 0xad760d6a, 0x2be27fc4, 0xe0beac61,
0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97,
0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa,
0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, 0xc01df89f, 0x0b412b3a,
0xfa1799ef, 0x314b4a4a, 0xb7df38e4, 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957,
0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, 0x089729a1,
0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, 0xe4c4abcc,
},
{
0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, 0xc5a73e8e,
0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, 0xf64870e9,
0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240,
0x5431d2a9, 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, 0x9196ec27,
0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712,
0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975,
0xa863a552, 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, 0x6dc49bdc,
0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb,
0x440b7579, 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7,
0x77e43b1e, 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590,
0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, 0x71edc610, 0x4005dc8d, 0xe672d739,
0x103aa7d0, 0xb64dac64, 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e,
0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b,
0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, 0xdb8937b8, 0x7dfe3c0c,
0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5,
0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2,
0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, 0x4db1d47c,
0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b,
0xefc8763c, 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, 0x2a6f48b2,
0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5,
0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0,
0x74449d09, 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, 0xb1e3a387,
0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e,
0x139a01c7, 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49,
0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105,
0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62,
0xabc30345, 0x0db408f1, 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb,
0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac,
0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, 0x6070932d, 0xc6079899,
0x304fe870, 0x9638e3c4, 0xa7d0f959, 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe,
0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, 0xa1d90457,
0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, 0x92364a30,
},
{
0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919,
0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, 0xd92012ac,
0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832,
0xaf5e2a9e, 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, 0xa59b2387,
0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f,
0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa,
0x85cd537d, 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, 0x8f085a64,
0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1,
0x299dc2ed, 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4,
0xfa78d958, 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041,
0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf,
0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a,
0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2,
0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, 0xc561b289, 0x09cbb217,
0xac509190, 0x60fa910e, 0xee7596ed, 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889,
0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, 0x7570833c,
0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3,
0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776,
0x2f80b4f1, 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, 0x2545bde8,
0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d,
0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95,
0x79a8fc39, 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, 0x736df520,
0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe,
0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b,
0x7aa64737, 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e,
0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, 0xe1a352e6, 0x6f2c5505, 0xa386559b,
0x061d761c, 0xcab77682, 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05,
0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0,
0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, 0x45bf2ce6, 0x89152c78,
0x50353ed4, 0x9c9f3e4a, 0x121039a9, 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd,
0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53,
0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6,
},
};
/*
@(optimization_mode="speed")
crc32 :: proc(data: []byte, seed := u32(0)) -> u32 {
result := ~u32(seed);
#no_bounds_check for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
@private _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
*/
+49 -7
View File
@@ -1,17 +1,52 @@
package hash
import "core:mem"
import "intrinsics"
@(optimization_mode="speed")
adler32 :: proc(data: []byte, seed := u32(1)) -> u32 #no_bounds_check {
adler32 :: proc(data: []byte, seed := u32(1)) -> u32 {
ADLER_CONST :: 65521;
a, b: u32 = seed & 0xFFFF, seed >> 16;
for x in data {
a = (a + u32(x)) % ADLER_CONST;
b = (b + a) % ADLER_CONST;
buffer := raw_data(data);
a, b: u64 = u64(seed) & 0xFFFF, u64(seed) >> 16;
buf := data[:];
for len(buf) != 0 && uintptr(buffer) & 7 != 0 {
a = (a + u64(buf[0]));
b = (b + a);
buffer = intrinsics.ptr_offset(buffer, 1);
buf = buf[1:];
}
return (b << 16) | a;
for len(buf) > 7 {
count := min(len(buf), 5552);
for count > 7 {
a += u64(buf[0]); b += a;
a += u64(buf[1]); b += a;
a += u64(buf[2]); b += a;
a += u64(buf[3]); b += a;
a += u64(buf[4]); b += a;
a += u64(buf[5]); b += a;
a += u64(buf[6]); b += a;
a += u64(buf[7]); b += a;
buf = buf[8:];
count -= 8;
}
a %= ADLER_CONST;
b %= ADLER_CONST;
}
for len(buf) != 0 {
a = (a + u64(buf[0])) % ADLER_CONST;
b = (b + a) % ADLER_CONST;
buf = buf[1:];
}
return (u32(b) << 16) | u32(a);
}
@(optimization_mode="speed")
djb2 :: proc(data: []byte) -> u32 {
hash: u32 = 5381;
for b in data {
@@ -20,6 +55,7 @@ djb2 :: proc(data: []byte) -> u32 {
return hash;
}
@(optimization_mode="speed")
fnv32 :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
@@ -28,6 +64,7 @@ fnv32 :: proc(data: []byte) -> u32 {
return h;
}
@(optimization_mode="speed")
fnv64 :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
@@ -36,6 +73,7 @@ fnv64 :: proc(data: []byte) -> u64 {
return h;
}
@(optimization_mode="speed")
fnv32a :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
@@ -44,6 +82,7 @@ fnv32a :: proc(data: []byte) -> u32 {
return h;
}
@(optimization_mode="speed")
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
@@ -52,6 +91,7 @@ fnv64a :: proc(data: []byte) -> u64 {
return h;
}
@(optimization_mode="speed")
jenkins :: proc(data: []byte) -> u32 {
hash: u32 = 0;
for b in data {
@@ -65,6 +105,7 @@ jenkins :: proc(data: []byte) -> u32 {
return hash;
}
@(optimization_mode="speed")
murmur32 :: proc(data: []byte) -> u32 {
c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593;
@@ -114,6 +155,7 @@ murmur32 :: proc(data: []byte) -> u32 {
return h1;
}
@(optimization_mode="speed")
murmur64 :: proc(data: []byte) -> u64 {
SEED :: 0x9747b28c;
@@ -219,7 +261,7 @@ murmur64 :: proc(data: []byte) -> u64 {
}
}
@(optimization_mode="speed")
sdbm :: proc(data: []byte) -> u32 {
hash: u32 = 0;
for b in data {
+214
View File
@@ -0,0 +1,214 @@
package image
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
Ginger Bill: Cosmetic changes.
*/
import "core:bytes"
import "core:mem"
Image :: struct {
width: int,
height: int,
channels: int,
depth: int,
pixels: bytes.Buffer,
/*
Some image loaders/writers can return/take an optional background color.
For convenience, we return them as u16 so we don't need to switch on the type
in our viewer, and can just test against nil.
*/
background: Maybe([3]u16),
metadata_ptr: rawptr,
metadata_type: typeid,
}
/*
IMPORTANT: `.do_not_expand_*` options currently skip handling of the `alpha_*` options,
therefore Gray+Alpha will be returned as such even if you add `.alpha_drop_if_present`,
and `.alpha_add_if_missing` and keyed transparency will likewise be ignored.
The same goes for indexed images. This will be remedied in a near future update.
*/
/*
Image_Option:
`.info`
This option behaves as `.return_ihdr` and `.do_not_decompress_image` and can be used
to gather an image's dimensions and color information.
`.return_header`
Fill out img.sidecar.header with the image's format-specific header struct.
If we only care about the image specs, we can set `.return_header` +
`.do_not_decompress_image`, or `.info`, which works as if both of these were set.
`.return_metadata`
Returns all chunks not needed to decode the data.
It also returns the header as if `.return_header` was set.
`.do_not_decompress_image`
Skip decompressing IDAT chunk, defiltering and the rest.
`.do_not_expand_grayscale`
Do not turn grayscale (+ Alpha) images into RGB(A).
Returns just the 1 or 2 channels present, although 1, 2 and 4 bit are still scaled to 8-bit.
`.do_not_expand_indexed`
Do not turn indexed (+ Alpha) images into RGB(A).
Returns just the 1 or 2 (with `tRNS`) channels present.
Make sure to use `return_metadata` to also return the palette chunk so you can recolor it yourself.
`.do_not_expand_channels`
Applies both `.do_not_expand_grayscale` and `.do_not_expand_indexed`.
`.alpha_add_if_missing`
If the image has no alpha channel, it'll add one set to max(type).
Turns RGB into RGBA and Gray into Gray+Alpha
`.alpha_drop_if_present`
If the image has an alpha channel, drop it.
You may want to use `.alpha_premultiply` in this case.
NOTE: For PNG, this also skips handling of the tRNS chunk, if present,
unless you select `alpha_premultiply`.
In this case it'll premultiply the specified pixels in question only,
as the others are implicitly fully opaque.
`.alpha_premultiply`
If the image has an alpha channel, returns image data as follows:
RGB *= A, Gray = Gray *= A
`.blend_background`
If a bKGD chunk is present in a PNG, we normally just set `img.background`
with its value and leave it up to the application to decide how to display the image,
as per the PNG specification.
With `.blend_background` selected, we blend the image against the background
color. As this negates the use for an alpha channel, we'll drop it _unless_
you also specify `.alpha_add_if_missing`.
Options that don't apply to an image format will be ignored by their loader.
*/
Option :: enum {
info = 0,
do_not_decompress_image,
return_header,
return_metadata,
alpha_add_if_missing,
alpha_drop_if_present,
alpha_premultiply,
blend_background,
// Unimplemented
do_not_expand_grayscale,
do_not_expand_indexed,
do_not_expand_channels,
}
Options :: distinct bit_set[Option];
Error :: enum {
Invalid_PNG_Signature,
IHDR_Not_First_Chunk,
IHDR_Corrupt,
IDAT_Missing,
IDAT_Must_Be_Contiguous,
IDAT_Corrupt,
PNG_Does_Not_Adhere_to_Spec,
PLTE_Encountered_Unexpectedly,
PLTE_Invalid_Length,
TRNS_Encountered_Unexpectedly,
BKGD_Invalid_Length,
Invalid_Image_Dimensions,
Unknown_Color_Type,
Invalid_Color_Bit_Depth_Combo,
Unknown_Filter_Method,
Unknown_Interlace_Method,
Requested_Channel_Not_Present,
Post_Processing_Error,
}
/*
Functions to help with image buffer calculations
*/
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height;
return;
}
/*
For when you have an RGB(A) image, but want a particular channel.
*/
Channel :: enum u8 {
R = 1,
G = 2,
B = 3,
A = 4,
}
return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok: bool) {
ok = false;
t: bytes.Buffer;
idx := int(channel);
if img.channels == 2 && idx == 4 {
// Alpha requested, which in a two channel image is index 2: G.
idx = 2;
}
if idx > img.channels {
return {}, false;
}
switch img.depth {
case 8:
buffer_size := compute_buffer_size(img.width, img.height, 1, 8);
t = bytes.Buffer{};
resize(&t.buf, buffer_size);
i := bytes.buffer_to_bytes(&img.pixels);
o := bytes.buffer_to_bytes(&t);
for len(i) > 0 {
o[0] = i[idx];
i = i[img.channels:];
o = o[1:];
}
case 16:
buffer_size := compute_buffer_size(img.width, img.height, 2, 8);
t = bytes.Buffer{};
resize(&t.buf, buffer_size);
i := mem.slice_data_cast([]u16, img.pixels.buf[:]);
o := mem.slice_data_cast([]u16, t.buf[:]);
for len(i) > 0 {
o[0] = i[idx];
i = i[img.channels:];
o = o[1:];
}
case 1, 2, 4:
// We shouldn't see this case, as the loader already turns these into 8-bit.
return {}, false;
}
res = new(Image);
res.width = img.width;
res.height = img.height;
res.channels = 1;
res.depth = img.depth;
res.pixels = t;
res.background = img.background;
res.metadata_ptr = img.metadata_ptr;
res.metadata_type = img.metadata_type;
return res, true;
}
+354
View File
@@ -0,0 +1,354 @@
//+ignore
package png
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
Ginger Bill: Cosmetic changes.
An example of how to use `load`.
*/
import "core:compress"
import "core:image"
// import "core:image/png"
import "core:bytes"
import "core:fmt"
// For PPM writer
import "core:mem"
import "core:os"
main :: proc() {
track := mem.Tracking_Allocator{};
mem.tracking_allocator_init(&track, context.allocator);
context.allocator = mem.tracking_allocator(&track);
demo();
if len(track.allocation_map) > 0 {
fmt.println("Leaks:");
for _, v in track.allocation_map {
fmt.printf("\t%v\n\n", v);
}
}
}
demo :: proc() {
file: string;
options := image.Options{}; // {.return_metadata};
err: compress.Error;
img: ^image.Image;
file = "../../../misc/logo-slim.png";
img, err = load(file, options);
defer destroy(img);
if err != nil {
fmt.printf("Trying to read PNG file %v returned %v\n", file, err);
} else {
v: ^Info;
fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth);
if img.metadata_ptr != nil && img.metadata_type == Info {
v = (^Info)(img.metadata_ptr);
// Handle ancillary chunks as you wish.
// We provide helper functions for a few types.
for c in v.chunks {
#partial switch c.header.type {
case .tIME:
t, _ := core_time(c);
fmt.printf("[tIME]: %v\n", t);
case .gAMA:
fmt.printf("[gAMA]: %v\n", gamma(c));
case .pHYs:
phys := phys(c);
if phys.unit == .Meter {
xm := f32(img.width) / f32(phys.ppu_x);
ym := f32(img.height) / f32(phys.ppu_y);
dpi_x, dpi_y := phys_to_dpi(phys);
fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y);
fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y);
fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym);
} else {
fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y);
}
case .iTXt, .zTXt, .tEXt:
res, ok_text := text(c);
if ok_text {
if c.header.type == .iTXt {
fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text);
} else {
fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text);
}
}
defer text_destroy(res);
case .bKGD:
fmt.printf("[bKGD] %v\n", img.background);
case .eXIf:
res, ok_exif := exif(c);
if ok_exif {
/*
Other than checking the signature and byte order, we don't handle Exif data.
If you wish to interpret it, pass it to an Exif parser.
*/
fmt.printf("[eXIf] %v\n", res);
}
case .PLTE:
plte, plte_ok := plte(c);
if plte_ok {
fmt.printf("[PLTE] %v\n", plte);
} else {
fmt.printf("[PLTE] Error\n");
}
case .hIST:
res, ok_hist := hist(c);
if ok_hist {
fmt.printf("[hIST] %v\n", res);
}
case .cHRM:
res, ok_chrm := chrm(c);
if ok_chrm {
fmt.printf("[cHRM] %v\n", res);
}
case .sPLT:
res, ok_splt := splt(c);
if ok_splt {
fmt.printf("[sPLT] %v\n", res);
}
splt_destroy(res);
case .sBIT:
if res, ok_sbit := sbit(c); ok_sbit {
fmt.printf("[sBIT] %v\n", res);
}
case .iCCP:
res, ok_iccp := iccp(c);
if ok_iccp {
fmt.printf("[iCCP] %v\n", res);
}
iccp_destroy(res);
case .sRGB:
if res, ok_srgb := srgb(c); ok_srgb {
fmt.printf("[sRGB] Rendering intent: %v\n", res);
}
case:
type := c.header.type;
name := chunk_type_to_name(&type);
fmt.printf("[%v]: %v\n", name, c.data);
}
}
}
}
if err == nil && .do_not_decompress_image not_in options && .info not_in options {
if ok := write_image_as_ppm("out.ppm", img); ok {
fmt.println("Saved decoded image.");
} else {
fmt.println("Error saving out.ppm.");
fmt.println(img);
}
}
}
// Crappy PPM writer used during testing. Don't use in production.
write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) {
_bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) {
if v, ok := bg.?; ok {
res = v;
} else {
if high {
l := u16(30 * 256 + 30);
if (x & 4 == 0) ~ (y & 4 == 0) {
res = [3]u16{l, 0, l};
} else {
res = [3]u16{l >> 1, 0, l >> 1};
}
} else {
if (x & 4 == 0) ~ (y & 4 == 0) {
res = [3]u16{30, 30, 30};
} else {
res = [3]u16{15, 15, 15};
}
}
}
return;
}
// profiler.timed_proc();
using image;
using os;
flags: int = O_WRONLY|O_CREATE|O_TRUNC;
img := image;
// PBM 16-bit images are big endian
when ODIN_ENDIAN == "little" {
if img.depth == 16 {
// The pixel components are in Big Endian. Let's byteswap back.
input := mem.slice_data_cast([]u16, img.pixels.buf[:]);
output := mem.slice_data_cast([]u16be, img.pixels.buf[:]);
#no_bounds_check for v, i in input {
output[i] = u16be(v);
}
}
}
pix := bytes.buffer_to_bytes(&img.pixels);
if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) {
return false;
}
mode: int = 0;
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
// NOTE(justasd): 644 (owner read, write; group read; others read)
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
}
fd, err := open(filename, flags, mode);
if err != 0 {
return false;
}
defer close(fd);
write_string(fd,
fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) - 1)),
);
if channels == 3 {
// We don't handle transparency here...
write_ptr(fd, raw_data(pix), len(pix));
} else {
bpp := depth == 16 ? 2 : 1;
bytes_needed := width * height * 3 * bpp;
op := bytes.Buffer{};
bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed);
defer bytes.buffer_destroy(&op);
if channels == 1 {
if depth == 16 {
assert(len(pix) == width * height * 2);
p16 := mem.slice_data_cast([]u16, pix);
o16 := mem.slice_data_cast([]u16, op.buf[:]);
#no_bounds_check for len(p16) != 0 {
r := u16(p16[0]);
o16[0] = r;
o16[1] = r;
o16[2] = r;
p16 = p16[1:];
o16 = o16[3:];
}
} else {
o := 0;
for i := 0; i < len(pix); i += 1 {
r := pix[i];
op.buf[o ] = r;
op.buf[o+1] = r;
op.buf[o+2] = r;
o += 3;
}
}
write_ptr(fd, raw_data(op.buf), len(op.buf));
} else if channels == 2 {
if depth == 16 {
p16 := mem.slice_data_cast([]u16, pix);
o16 := mem.slice_data_cast([]u16, op.buf[:]);
bgcol := img.background;
#no_bounds_check for len(p16) != 0 {
r := f64(u16(p16[0]));
bg: f64;
if bgcol != nil {
v := bgcol.([3]u16)[0];
bg = f64(v);
}
a := f64(u16(p16[1])) / 65535.0;
l := (a * r) + (1 - a) * bg;
o16[0] = u16(l);
o16[1] = u16(l);
o16[2] = u16(l);
p16 = p16[2:];
o16 = o16[3:];
}
} else {
o := 0;
for i := 0; i < len(pix); i += 2 {
r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0;
c := u8(f32(r) * a1);
op.buf[o ] = c;
op.buf[o+1] = c;
op.buf[o+2] = c;
o += 3;
}
}
write_ptr(fd, raw_data(op.buf), len(op.buf));
} else if channels == 4 {
if depth == 16 {
p16 := mem.slice_data_cast([]u16be, pix);
o16 := mem.slice_data_cast([]u16be, op.buf[:]);
#no_bounds_check for len(p16) != 0 {
bg := _bg(img.background, 0, 0);
r := f32(p16[0]);
g := f32(p16[1]);
b := f32(p16[2]);
a := f32(p16[3]) / 65535.0;
lr := (a * r) + (1 - a) * f32(bg[0]);
lg := (a * g) + (1 - a) * f32(bg[1]);
lb := (a * b) + (1 - a) * f32(bg[2]);
o16[0] = u16be(lr);
o16[1] = u16be(lg);
o16[2] = u16be(lb);
p16 = p16[4:];
o16 = o16[3:];
}
} else {
o := 0;
for i := 0; i < len(pix); i += 4 {
x := (i / 4) % width;
y := i / width / 4;
_b := _bg(img.background, x, y, false);
bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])};
r := f32(pix[i]);
g := f32(pix[i+1]);
b := f32(pix[i+2]);
a := f32(pix[i+3]) / 255.0;
lr := u8(f32(r) * a + (1 - a) * f32(bgcol[0]));
lg := u8(f32(g) * a + (1 - a) * f32(bgcol[1]));
lb := u8(f32(b) * a + (1 - a) * f32(bgcol[2]));
op.buf[o ] = lr;
op.buf[o+1] = lg;
op.buf[o+2] = lb;
o += 3;
}
}
write_ptr(fd, raw_data(op.buf), len(op.buf));
} else {
return false;
}
}
return true;
}
+525
View File
@@ -0,0 +1,525 @@
package png
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
Ginger Bill: Cosmetic changes.
These are a few useful utility functions to work with PNG images.
*/
import "core:image"
import "core:compress/zlib"
import coretime "core:time"
import "core:strings"
import "core:bytes"
import "core:mem"
/*
Cleanup of image-specific data.
There are other helpers for cleanup of PNG-specific data.
Those are named *_destroy, where * is the name of the helper.
*/
destroy :: proc(img: ^Image) {
if img == nil {
/*
Nothing to do.
Load must've returned with an error.
*/
return;
}
bytes.buffer_destroy(&img.pixels);
// Clean up Info.
free(img.metadata_ptr);
/*
We don't need to do anything for the individual chunks.
They're allocated on the temp allocator, as is info.chunks
See read_chunk.
*/
free(img);
}
/*
Chunk helpers
*/
gamma :: proc(c: Chunk) -> f32 {
assert(c.header.type == .gAMA);
res := (^gAMA)(raw_data(c.data))^;
when true {
// Returns the wrong result on old backend
// Fixed for -llvm-api
return f32(res.gamma_100k) / 100_000.0;
} else {
return f32(u32(res.gamma_100k)) / 100_000.0;
}
}
INCHES_PER_METER :: 1000.0 / 25.4;
phys :: proc(c: Chunk) -> pHYs {
assert(c.header.type == .pHYs);
res := (^pHYs)(raw_data(c.data))^;
return res;
}
phys_to_dpi :: proc(p: pHYs) -> (x_dpi, y_dpi: f32) {
return f32(p.ppu_x) / INCHES_PER_METER, f32(p.ppu_y) / INCHES_PER_METER;
}
time :: proc(c: Chunk) -> tIME {
assert(c.header.type == .tIME);
res := (^tIME)(raw_data(c.data))^;
return res;
}
core_time :: proc(c: Chunk) -> (t: coretime.Time, ok: bool) {
png_time := time(c);
using png_time;
return coretime.datetime_to_time(
int(year), int(month), int(day),
int(hour), int(minute), int(second),
);
}
text :: proc(c: Chunk) -> (res: Text, ok: bool) {
#partial switch c.header.type {
case .tEXt:
ok = true;
fields := bytes.split(s=c.data, sep=[]u8{0}, allocator=context.temp_allocator);
if len(fields) == 2 {
res.keyword = strings.clone(string(fields[0]));
res.text = strings.clone(string(fields[1]));
} else {
ok = false;
}
return;
case .zTXt:
ok = true;
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator);
if len(fields) != 3 || len(fields[1]) != 0 {
// Compression method must be 0=Deflate, which thanks to the split above turns
// into an empty slice
ok = false; return;
}
// Set up ZLIB context and decompress text payload.
buf: bytes.Buffer;
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf);
defer bytes.buffer_destroy(&buf);
if zlib_error != nil {
ok = false; return;
}
res.keyword = strings.clone(string(fields[0]));
res.text = strings.clone(bytes.buffer_to_string(&buf));
return;
case .iTXt:
ok = true;
s := string(c.data);
null := strings.index_byte(s, 0);
if null == -1 {
ok = false; return;
}
if len(c.data) < null + 4 {
// At a minimum, including the \0 following the keyword, we require 5 more bytes.
ok = false; return;
}
res.keyword = strings.clone(string(c.data[:null]));
rest := c.data[null+1:];
compression_flag := rest[:1][0];
if compression_flag > 1 {
ok = false; return;
}
compression_method := rest[1:2][0];
if compression_flag == 1 && compression_method > 0 {
// Only Deflate is supported
ok = false; return;
}
rest = rest[2:];
// We now expect an optional language keyword and translated keyword, both followed by a \0
null = strings.index_byte(string(rest), 0);
if null == -1 {
ok = false; return;
}
res.language = strings.clone(string(rest[:null]));
rest = rest[null+1:];
null = strings.index_byte(string(rest), 0);
if null == -1 {
ok = false; return;
}
res.keyword_localized = strings.clone(string(rest[:null]));
rest = rest[null+1:];
if compression_flag == 0 {
res.text = strings.clone(string(rest));
} else {
// Set up ZLIB context and decompress text payload.
buf: bytes.Buffer;
zlib_error := zlib.inflate_from_byte_array(rest, &buf);
defer bytes.buffer_destroy(&buf);
if zlib_error != nil {
ok = false; return;
}
res.text = strings.clone(bytes.buffer_to_string(&buf));
}
return;
case:
// PNG text helper called with an unrecognized chunk type.
ok = false; return;
}
}
text_destroy :: proc(text: Text) {
delete(text.keyword);
delete(text.keyword_localized);
delete(text.language);
delete(text.text);
}
iccp :: proc(c: Chunk) -> (res: iCCP, ok: bool) {
ok = true;
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator);
if len(fields[0]) < 1 || len(fields[0]) > 79 {
// Invalid profile name
ok = false; return;
}
if len(fields[1]) != 0 {
// Compression method should be a zero, which the split turned into an empty slice.
ok = false; return;
}
// Set up ZLIB context and decompress iCCP payload
buf: bytes.Buffer;
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf);
if zlib_error != nil {
bytes.buffer_destroy(&buf);
ok = false; return;
}
res.name = strings.clone(string(fields[0]));
res.profile = bytes.buffer_to_bytes(&buf);
return;
}
iccp_destroy :: proc(i: iCCP) {
delete(i.name);
delete(i.profile);
}
srgb :: proc(c: Chunk) -> (res: sRGB, ok: bool) {
ok = true;
if c.header.type != .sRGB || len(c.data) != 1 {
return {}, false;
}
res.intent = sRGB_Rendering_Intent(c.data[0]);
if res.intent > max(sRGB_Rendering_Intent) {
ok = false; return;
}
return;
}
plte :: proc(c: Chunk) -> (res: PLTE, ok: bool) {
if c.header.type != .PLTE {
return {}, false;
}
i := 0; j := 0; ok = true;
for j < int(c.header.length) {
res.entries[i] = {c.data[j], c.data[j+1], c.data[j+2]};
i += 1; j += 3;
}
res.used = u16(i);
return;
}
splt :: proc(c: Chunk) -> (res: sPLT, ok: bool) {
if c.header.type != .sPLT {
return {}, false;
}
ok = true;
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator);
if len(fields) != 2 {
return {}, false;
}
res.depth = fields[1][0];
if res.depth != 8 && res.depth != 16 {
return {}, false;
}
data := fields[1][1:];
count: int;
if res.depth == 8 {
if len(data) % 6 != 0 {
return {}, false;
}
count = len(data) / 6;
if count > 256 {
return {}, false;
}
res.entries = mem.slice_data_cast([][4]u8, data);
} else { // res.depth == 16
if len(data) % 10 != 0 {
return {}, false;
}
count = len(data) / 10;
if count > 256 {
return {}, false;
}
res.entries = mem.slice_data_cast([][4]u16, data);
}
res.name = strings.clone(string(fields[0]));
res.used = u16(count);
return;
}
splt_destroy :: proc(s: sPLT) {
delete(s.name);
}
sbit :: proc(c: Chunk) -> (res: [4]u8, ok: bool) {
/*
Returns [4]u8 with the significant bits in each channel.
A channel will contain zero if not applicable to the PNG color type.
*/
if len(c.data) < 1 || len(c.data) > 4 {
ok = false; return;
}
ok = true;
for i := 0; i < len(c.data); i += 1 {
res[i] = c.data[i];
}
return;
}
hist :: proc(c: Chunk) -> (res: hIST, ok: bool) {
if c.header.type != .hIST {
return {}, false;
}
if c.header.length & 1 == 1 || c.header.length > 512 {
// The entries are u16be, so the length must be even.
// At most 256 entries must be present
return {}, false;
}
ok = true;
data := mem.slice_data_cast([]u16be, c.data);
i := 0;
for len(data) > 0 {
// HIST entries are u16be, we unpack them to machine format
res.entries[i] = u16(data[0]);
i += 1; data = data[1:];
}
res.used = u16(i);
return;
}
chrm :: proc(c: Chunk) -> (res: cHRM, ok: bool) {
ok = true;
if c.header.length != size_of(cHRM_Raw) {
return {}, false;
}
chrm := (^cHRM_Raw)(raw_data(c.data))^;
res.w.x = f32(chrm.w.x) / 100_000.0;
res.w.y = f32(chrm.w.y) / 100_000.0;
res.r.x = f32(chrm.r.x) / 100_000.0;
res.r.y = f32(chrm.r.y) / 100_000.0;
res.g.x = f32(chrm.g.x) / 100_000.0;
res.g.y = f32(chrm.g.y) / 100_000.0;
res.b.x = f32(chrm.b.x) / 100_000.0;
res.b.y = f32(chrm.b.y) / 100_000.0;
return;
}
exif :: proc(c: Chunk) -> (res: Exif, ok: bool) {
ok = true;
if len(c.data) < 4 {
ok = false; return;
}
if c.data[0] == 'M' && c.data[1] == 'M' {
res.byte_order = .big_endian;
if c.data[2] != 0 || c.data[3] != 42 {
ok = false; return;
}
} else if c.data[0] == 'I' && c.data[1] == 'I' {
res.byte_order = .little_endian;
if c.data[2] != 42 || c.data[3] != 0 {
ok = false; return;
}
} else {
ok = false; return;
}
res.data = c.data;
return;
}
/*
General helper functions
*/
compute_buffer_size :: image.compute_buffer_size;
/*
PNG save helpers
*/
when false {
make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) {
data: []u8;
if v, ok := c.([]u8); ok {
data = v;
} else {
data = mem.any_to_bytes(c);
}
res.header.length = u32be(len(data));
res.header.type = t;
res.data = data;
// CRC the type
crc := hash.crc32(mem.any_to_bytes(res.header.type));
// Extend the CRC with the data
res.crc = u32be(hash.crc32(data, crc));
return;
}
write_chunk :: proc(fd: os.Handle, chunk: Chunk) {
c := chunk;
// Write length + type
os.write_ptr(fd, &c.header, 8);
// Write data
os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length));
// Write CRC32
os.write_ptr(fd, &c.crc, 4);
}
write_image_as_png :: proc(filename: string, image: Image) -> (err: Error) {
profiler.timed_proc();
using image;
using os;
flags: int = O_WRONLY|O_CREATE|O_TRUNC;
if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
return E_PNG.Invalid_Image_Dimensions;
}
mode: int = 0;
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
// NOTE(justasd): 644 (owner read, write; group read; others read)
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
}
fd, fderr := open(filename, flags, mode);
if fderr != 0 {
return E_General.Cannot_Open_File;
}
defer close(fd);
magic := Signature;
write_ptr(fd, &magic, 8);
ihdr := IHDR{
width = u32be(width),
height = u32be(height),
bit_depth = depth,
compression_method = 0,
filter_method = 0,
interlace_method = .None,
};
switch channels {
case 1: ihdr.color_type = Color_Type{};
case 2: ihdr.color_type = Color_Type{.Alpha};
case 3: ihdr.color_type = Color_Type{.Color};
case 4: ihdr.color_type = Color_Type{.Color, .Alpha};
case:// Unhandled
return E_PNG.Unknown_Color_Type;
}
h := make_chunk(ihdr, .IHDR);
write_chunk(fd, h);
bytes_needed := width * height * int(channels) + height;
filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator);
defer delete(filter_bytes);
i := 0; j := 0;
// Add a filter byte 0 per pixel row
for y := 0; y < height; y += 1 {
filter_bytes[j] = 0; j += 1;
for x := 0; x < width; x += 1 {
for z := 0; z < channels; z += 1 {
filter_bytes[j+z] = image.pixels[i+z];
}
i += channels; j += channels;
}
}
assert(j == bytes_needed);
a: []u8 = filter_bytes[:];
out_buf: ^[dynamic]u8;
defer free(out_buf);
ctx := zlib.ZLIB_Context{
in_buf = &a,
out_buf = out_buf,
};
err = zlib.write_zlib_stream_from_memory(&ctx);
b: []u8;
if err == nil {
b = ctx.out_buf[:];
} else {
return err;
}
idat := make_chunk(b, .IDAT);
write_chunk(fd, idat);
iend := make_chunk([]u8{}, .IEND);
write_chunk(fd, iend);
return nil;
}
}
File diff suppressed because it is too large Load Diff
+56 -32
View File
@@ -12,7 +12,40 @@ volatile_store :: proc(dst: ^$T, val: T) -> T ---
// Trapping
debug_trap :: proc() ---
trap :: proc() -> ! ---
trap :: proc() -> ! ---
// Instructions
alloca :: proc(size, align: int) -> ^u8 ---
cpu_relax :: proc() ---
read_cycle_counter :: proc() -> i64 ---
count_ones :: proc(x: $T) -> T where type_is_integer(T) ---
count_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
reverse_bits :: proc(x: $T) -> T where type_is_integer(T) ---
byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) ---
overflow_add :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
sqrt :: proc(x: $T) -> T where type_is_float(T) ---
mem_copy :: proc(dst, src: rawptr, len: int) ---
mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) ---
mem_zero :: proc(ptr: rawptr, len: int) ---
fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
fixed_point_div :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
fixed_point_mul_sat :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
fixed_point_div_sat :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
// Compiler Hints
expect :: proc(val, expected_val: T) -> T ---
// Atomics
atomic_fence :: proc() ---
@@ -67,36 +100,25 @@ atomic_xchg_rel :: proc(dst; ^$T, val: T) -> T ---
atomic_xchg_acqrel :: proc(dst; ^$T, val: T) -> T ---
atomic_xchg_relaxed :: proc(dst; ^$T, val: T) -> T ---
atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
// Instructions
alloca :: proc(size, align: int) -> ^u8 ---
cpu_relax :: proc() ---
read_cycle_counter :: proc() -> i64 ---
// Compiler Hints
expect :: proc(val, expected_val: T) -> T ---
atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
// Constant type tests
@@ -114,6 +136,7 @@ type_is_string :: proc($T: typeid) -> bool ---
type_is_typeid :: proc($T: typeid) -> bool ---
type_is_any :: proc($T: typeid) -> bool ---
type_is_endian_platform :: proc($T: typeid) -> bool ---
type_is_endian_little :: proc($T: typeid) -> bool ---
type_is_endian_big :: proc($T: typeid) -> bool ---
type_is_unsigned :: proc($T: typeid) -> bool ---
@@ -144,6 +167,7 @@ type_is_simd_vector :: proc($T: typeid) -> bool ---
type_has_nil :: proc($T: typeid) -> bool ---
type_is_specialization_of :: proc($T, $S: typeid) -> bool ---
type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) ---
type_has_field :: proc($T: typeid, $name: string) -> bool ---
@@ -159,5 +183,5 @@ type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V --
type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) ---
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) ---
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) ---
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
+13 -214
View File
@@ -1,6 +1,6 @@
package math_bits
import "core:runtime"
import "intrinsics"
U8_MIN :: 0;
U16_MIN :: 0;
@@ -22,105 +22,19 @@ I16_MAX :: 1 << 15 - 1;
I32_MAX :: 1 << 31 - 1;
I64_MAX :: 1 << 63 - 1;
@(default_calling_convention="none")
foreign {
@(link_name="llvm.ctpop.i8") count_ones8 :: proc(i: u8) -> u8 ---
@(link_name="llvm.ctpop.i16") count_ones16 :: proc(i: u16) -> u16 ---
@(link_name="llvm.ctpop.i32") count_ones32 :: proc(i: u32) -> u32 ---
@(link_name="llvm.ctpop.i64") count_ones64 :: proc(i: u64) -> u64 ---
@(link_name="llvm.cttz.i8") trailing_zeros8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.cttz.i16") trailing_zeros16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.cttz.i32") trailing_zeros32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.cttz.i64") trailing_zeros64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
count_ones :: intrinsics.count_ones;
count_zeros :: intrinsics.count_zeros;
trailing_zeros :: intrinsics.count_trailing_zeros;
leading_zeros :: intrinsics.count_leading_zeros;
count_trailing_zeros :: intrinsics.count_trailing_zeros;
count_leading_zeros :: intrinsics.count_leading_zeros;
reverse_bits :: intrinsics.reverse_bits;
byte_swap :: intrinsics.byte_swap;
@(link_name="llvm.bitreverse.i8") reverse_bits8 :: proc(i: u8) -> u8 ---
@(link_name="llvm.bitreverse.i16") reverse_bits16 :: proc(i: u16) -> u16 ---
@(link_name="llvm.bitreverse.i32") reverse_bits32 :: proc(i: u32) -> u32 ---
@(link_name="llvm.bitreverse.i64") reverse_bits64 :: proc(i: u64) -> u64 ---
}
trailing_zeros_uint :: proc(i: uint) -> uint {
when size_of(uint) == size_of(u64) {
return uint(trailing_zeros64(u64(i)));
} else {
return uint(trailing_zeros32(u32(i)));
}
}
leading_zeros_u8 :: proc(i: u8) -> int {
return 8*size_of(i) - len_u8(i);
}
leading_zeros_u16 :: proc(i: u16) -> int {
return 8*size_of(i) - len_u16(i);
}
leading_zeros_u32 :: proc(i: u32) -> int {
return 8*size_of(i) - len_u32(i);
}
leading_zeros_u64 :: proc(i: u64) -> int {
return 8*size_of(i) - len_u64(i);
}
byte_swap_u16 :: proc(x: u16) -> u16 {
return runtime.bswap_16(x);
}
byte_swap_u32 :: proc(x: u32) -> u32 {
return runtime.bswap_32(x);
}
byte_swap_u64 :: proc(x: u64) -> u64 {
return runtime.bswap_64(x);
}
byte_swap_i16 :: proc(x: i16) -> i16 {
return i16(runtime.bswap_16(u16(x)));
}
byte_swap_i32 :: proc(x: i32) -> i32 {
return i32(runtime.bswap_32(u32(x)));
}
byte_swap_i64 :: proc(x: i64) -> i64 {
return i64(runtime.bswap_64(u64(x)));
}
byte_swap_u128 :: proc(x: u128) -> u128 {
return runtime.bswap_128(x);
}
byte_swap_i128 :: proc(x: i128) -> i128 {
return i128(runtime.bswap_128(u128(x)));
}
byte_swap_uint :: proc(i: uint) -> uint {
when size_of(uint) == size_of(u32) {
return uint(byte_swap_u32(u32(i)));
} else {
return uint(byte_swap_u64(u64(i)));
}
}
byte_swap_int :: proc(i: int) -> int {
when size_of(int) == size_of(i32) {
return int(byte_swap_i32(i32(i)));
} else {
return int(byte_swap_i64(i64(i)));
}
}
byte_swap :: proc{
byte_swap_u16,
byte_swap_u32,
byte_swap_u64,
byte_swap_u128,
byte_swap_i16,
byte_swap_i32,
byte_swap_i64,
byte_swap_i128,
byte_swap_uint,
byte_swap_int,
};
count_zeros8 :: proc(i: u8) -> u8 { return 8 - count_ones8(i); }
count_zeros16 :: proc(i: u16) -> u16 { return 16 - count_ones16(i); }
count_zeros32 :: proc(i: u32) -> u32 { return 32 - count_ones32(i); }
count_zeros64 :: proc(i: u64) -> u64 { return 64 - count_ones64(i); }
overflowing_add :: intrinsics.overflow_add;
overflowing_sub :: intrinsics.overflow_sub;
overflowing_mul :: intrinsics.overflow_mul;
rotate_left8 :: proc(x: u8, k: int) -> u8 {
@@ -176,121 +90,6 @@ to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; }
to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
@(default_calling_convention="none")
foreign {
@(link_name="llvm.uadd.with.overflow.i8") overflowing_add_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
@(link_name="llvm.sadd.with.overflow.i8") overflowing_add_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
@(link_name="llvm.uadd.with.overflow.i16") overflowing_add_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
@(link_name="llvm.sadd.with.overflow.i16") overflowing_add_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
@(link_name="llvm.uadd.with.overflow.i32") overflowing_add_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
@(link_name="llvm.sadd.with.overflow.i32") overflowing_add_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
@(link_name="llvm.uadd.with.overflow.i64") overflowing_add_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
@(link_name="llvm.sadd.with.overflow.i64") overflowing_add_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
}
overflowing_add_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_add_u32(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_add_u64(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_add_int :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_add_i32(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_add_i64(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_add :: proc{
overflowing_add_u8, overflowing_add_i8,
overflowing_add_u16, overflowing_add_i16,
overflowing_add_u32, overflowing_add_i32,
overflowing_add_u64, overflowing_add_i64,
overflowing_add_uint, overflowing_add_int,
};
@(default_calling_convention="none")
foreign {
@(link_name="llvm.usub.with.overflow.i8") overflowing_sub_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
@(link_name="llvm.ssub.with.overflow.i8") overflowing_sub_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
@(link_name="llvm.usub.with.overflow.i16") overflowing_sub_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
@(link_name="llvm.ssub.with.overflow.i16") overflowing_sub_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
@(link_name="llvm.usub.with.overflow.i32") overflowing_sub_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
@(link_name="llvm.ssub.with.overflow.i32") overflowing_sub_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
@(link_name="llvm.usub.with.overflow.i64") overflowing_sub_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
@(link_name="llvm.ssub.with.overflow.i64") overflowing_sub_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
}
overflowing_sub_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_sub_u32(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_sub_u64(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_sub_int :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_sub_i32(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_sub_i64(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_sub :: proc{
overflowing_sub_u8, overflowing_sub_i8,
overflowing_sub_u16, overflowing_sub_i16,
overflowing_sub_u32, overflowing_sub_i32,
overflowing_sub_u64, overflowing_sub_i64,
overflowing_sub_uint, overflowing_sub_int,
};
@(default_calling_convention="none")
foreign {
@(link_name="llvm.umul.with.overflow.i8") overflowing_mul_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
@(link_name="llvm.smul.with.overflow.i8") overflowing_mul_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
@(link_name="llvm.umul.with.overflow.i16") overflowing_mul_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
@(link_name="llvm.smul.with.overflow.i16") overflowing_mul_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
@(link_name="llvm.umul.with.overflow.i32") overflowing_mul_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
@(link_name="llvm.smul.with.overflow.i32") overflowing_mul_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
@(link_name="llvm.umul.with.overflow.i64") overflowing_mul_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
@(link_name="llvm.smul.with.overflow.i64") overflowing_mul_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
}
overflowing_mul_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_mul_u32(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_mul_u64(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_mul_int :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_mul_i32(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_mul_i64(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_mul :: proc{
overflowing_mul_u8, overflowing_mul_i8,
overflowing_mul_u16, overflowing_mul_i16,
overflowing_mul_u32, overflowing_mul_i32,
overflowing_mul_u64, overflowing_mul_i64,
overflowing_mul_uint, overflowing_mul_int,
};
len_u8 :: proc(x: u8) -> int {
return int(len_u8_table[x]);
@@ -448,7 +247,7 @@ div_u64 :: proc(hi, lo, y: u64) -> (quo, rem: u64) {
panic("overflow error");
}
s := uint(leading_zeros_u64(y));
s := uint(count_leading_zeros(y));
y <<= s;
yn1 := y >> 32;
+1 -1
View File
@@ -6,7 +6,7 @@ import "core:strconv"
import "intrinsics"
_ :: intrinsics;
Fixed :: struct($Backing: typeid, Fraction_Width: uint)
Fixed :: struct($Backing: typeid, $Fraction_Width: uint)
where
intrinsics.type_is_integer(Backing),
0 <= Fraction_Width,
+1 -2
View File
@@ -170,8 +170,7 @@ trace :: proc(m: $T/[$N][N]$E) -> (tr: E) {
return;
}
transpose :: proc(a: $T/[$N][$M]$E) -> (m: T) {
transpose :: proc(a: $T/[$N][$M]$E) -> (m: (T when N == M else [M][N]E)) {
for j in 0..<M {
for i in 0..<N {
m[j][i] = a[i][j];
+6 -6
View File
@@ -1284,13 +1284,13 @@ matrix3_from_quaternion :: proc{
matrix3_inverse_f16 :: proc(m: Matrix3f16) -> Matrix3f16 {
return transpose(matrix3_inverse_transpose(m));
return auto_cast transpose(matrix3_inverse_transpose(m));
}
matrix3_inverse_f32 :: proc(m: Matrix3f32) -> Matrix3f32 {
return transpose(matrix3_inverse_transpose(m));
return auto_cast transpose(matrix3_inverse_transpose(m));
}
matrix3_inverse_f64 :: proc(m: Matrix3f64) -> Matrix3f64 {
return transpose(matrix3_inverse_transpose(m));
return auto_cast transpose(matrix3_inverse_transpose(m));
}
matrix3_inverse :: proc{
matrix3_inverse_f16,
@@ -1655,13 +1655,13 @@ matrix4_from_trs :: proc{
matrix4_inverse_f16 :: proc(m: Matrix4f16) -> Matrix4f16 {
return transpose(matrix4_inverse_transpose(m));
return auto_cast transpose(matrix4_inverse_transpose(m));
}
matrix4_inverse_f32 :: proc(m: Matrix4f32) -> Matrix4f32 {
return transpose(matrix4_inverse_transpose(m));
return auto_cast transpose(matrix4_inverse_transpose(m));
}
matrix4_inverse_f64 :: proc(m: Matrix4f64) -> Matrix4f64 {
return transpose(matrix4_inverse_transpose(m));
return auto_cast transpose(matrix4_inverse_transpose(m));
}
matrix4_inverse :: proc{
matrix4_inverse_f16,
+540 -165
View File
@@ -96,45 +96,186 @@ foreign _ {
ldexp_f64 :: proc(val: f64, exp: i32) -> f64 ---;
}
sqrt :: proc{sqrt_f16, sqrt_f32, sqrt_f64};
sin :: proc{sin_f16, sin_f32, sin_f64};
cos :: proc{cos_f16, cos_f32, cos_f64};
pow :: proc{pow_f16, pow_f32, pow_f64};
fmuladd :: proc{fmuladd_f16, fmuladd_f32, fmuladd_f64};
ln :: proc{ln_f16, ln_f32, ln_f64};
exp :: proc{exp_f16, exp_f32, exp_f64};
sqrt_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(sqrt_f16(f16(x))); }
sqrt_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(sqrt_f16(f16(x))); }
sqrt_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(sqrt_f32(f32(x))); }
sqrt_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(sqrt_f32(f32(x))); }
sqrt_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(sqrt_f64(f64(x))); }
sqrt_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(sqrt_f64(f64(x))); }
sqrt :: proc{
sqrt_f16, sqrt_f16le, sqrt_f16be,
sqrt_f32, sqrt_f32le, sqrt_f32be,
sqrt_f64, sqrt_f64le, sqrt_f64be,
};
ldexp :: proc{ldexp_f16, ldexp_f32, ldexp_f64};
sin_f16le :: proc(θ: f16le) -> f16le { return #force_inline f16le(sin_f16(f16(θ))); }
sin_f16be :: proc(θ: f16be) -> f16be { return #force_inline f16be(sin_f16(f16(θ))); }
sin_f32le :: proc(θ: f32le) -> f32le { return #force_inline f32le(sin_f32(f32(θ))); }
sin_f32be :: proc(θ: f32be) -> f32be { return #force_inline f32be(sin_f32(f32(θ))); }
sin_f64le :: proc(θ: f64le) -> f64le { return #force_inline f64le(sin_f64(f64(θ))); }
sin_f64be :: proc(θ: f64be) -> f64be { return #force_inline f64be(sin_f64(f64(θ))); }
sin :: proc{
sin_f16, sin_f16le, sin_f16be,
sin_f32, sin_f32le, sin_f32be,
sin_f64, sin_f64le, sin_f64be,
};
log_f16 :: proc(x, base: f16) -> f16 { return ln(x) / ln(base); }
log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
log :: proc{log_f16, log_f32, log_f64};
cos_f16le :: proc(θ: f16le) -> f16le { return #force_inline f16le(cos_f16(f16(θ))); }
cos_f16be :: proc(θ: f16be) -> f16be { return #force_inline f16be(cos_f16(f16(θ))); }
cos_f32le :: proc(θ: f32le) -> f32le { return #force_inline f32le(cos_f32(f32(θ))); }
cos_f32be :: proc(θ: f32be) -> f32be { return #force_inline f32be(cos_f32(f32(θ))); }
cos_f64le :: proc(θ: f64le) -> f64le { return #force_inline f64le(cos_f64(f64(θ))); }
cos_f64be :: proc(θ: f64be) -> f64be { return #force_inline f64be(cos_f64(f64(θ))); }
cos :: proc{
cos_f16, cos_f16le, cos_f16be,
cos_f32, cos_f32le, cos_f32be,
cos_f64, cos_f64le, cos_f64be,
};
log2_f16 :: proc(x: f16) -> f16 { return ln(x)/LN2; }
log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
log2 :: proc{log2_f16, log2_f32, log2_f64};
pow_f16le :: proc(x, power: f16le) -> f16le { return #force_inline f16le(pow_f16(f16(x), f16(power))); }
pow_f16be :: proc(x, power: f16be) -> f16be { return #force_inline f16be(pow_f16(f16(x), f16(power))); }
pow_f32le :: proc(x, power: f32le) -> f32le { return #force_inline f32le(pow_f32(f32(x), f32(power))); }
pow_f32be :: proc(x, power: f32be) -> f32be { return #force_inline f32be(pow_f32(f32(x), f32(power))); }
pow_f64le :: proc(x, power: f64le) -> f64le { return #force_inline f64le(pow_f64(f64(x), f64(power))); }
pow_f64be :: proc(x, power: f64be) -> f64be { return #force_inline f64be(pow_f64(f64(x), f64(power))); }
pow :: proc{
pow_f16, pow_f16le, pow_f16be,
pow_f32, pow_f32le, pow_f32be,
pow_f64, pow_f64le, pow_f64be,
};
log10_f16 :: proc(x: f16) -> f16 { return ln(x)/LN10; }
log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
log10 :: proc{log10_f16, log10_f32, log10_f64};
fmuladd_f16le :: proc(a, b, c: f16le) -> f16le { return #force_inline f16le(fmuladd_f16(f16(a), f16(b), f16(c))); }
fmuladd_f16be :: proc(a, b, c: f16be) -> f16be { return #force_inline f16be(fmuladd_f16(f16(a), f16(b), f16(c))); }
fmuladd_f32le :: proc(a, b, c: f32le) -> f32le { return #force_inline f32le(fmuladd_f32(f32(a), f32(b), f32(c))); }
fmuladd_f32be :: proc(a, b, c: f32be) -> f32be { return #force_inline f32be(fmuladd_f32(f32(a), f32(b), f32(c))); }
fmuladd_f64le :: proc(a, b, c: f64le) -> f64le { return #force_inline f64le(fmuladd_f64(f64(a), f64(b), f64(c))); }
fmuladd_f64be :: proc(a, b, c: f64be) -> f64be { return #force_inline f64be(fmuladd_f64(f64(a), f64(b), f64(c))); }
fmuladd :: proc{
fmuladd_f16, fmuladd_f16le, fmuladd_f16be,
fmuladd_f32, fmuladd_f32le, fmuladd_f32be,
fmuladd_f64, fmuladd_f64le, fmuladd_f64be,
};
ln_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(ln_f16(f16(x))); }
ln_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(ln_f16(f16(x))); }
ln_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(ln_f32(f32(x))); }
ln_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(ln_f32(f32(x))); }
ln_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))); }
ln_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))); }
ln :: proc{
ln_f16, ln_f16le, ln_f16be,
ln_f32, ln_f32le, ln_f32be,
ln_f64, ln_f64le, ln_f64be,
};
exp_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(exp_f16(f16(x))); }
exp_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(exp_f16(f16(x))); }
exp_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(exp_f32(f32(x))); }
exp_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(exp_f32(f32(x))); }
exp_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(exp_f64(f64(x))); }
exp_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(exp_f64(f64(x))); }
exp :: proc{
exp_f16, exp_f16le, exp_f16be,
exp_f32, exp_f32le, exp_f32be,
exp_f64, exp_f64le, exp_f64be,
};
ldexp_f16le :: proc(val: f16le, exp: i32) -> f16le { return #force_inline f16le(ldexp_f16(f16(val), exp)); }
ldexp_f16be :: proc(val: f16be, exp: i32) -> f16be { return #force_inline f16be(ldexp_f16(f16(val), exp)); }
ldexp_f32le :: proc(val: f32le, exp: i32) -> f32le { return #force_inline f32le(ldexp_f32(f32(val), exp)); }
ldexp_f32be :: proc(val: f32be, exp: i32) -> f32be { return #force_inline f32be(ldexp_f32(f32(val), exp)); }
ldexp_f64le :: proc(val: f64le, exp: i32) -> f64le { return #force_inline f64le(ldexp_f64(f64(val), exp)); }
ldexp_f64be :: proc(val: f64be, exp: i32) -> f64be { return #force_inline f64be(ldexp_f64(f64(val), exp)); }
ldexp :: proc{
ldexp_f16, ldexp_f16le, ldexp_f16be,
ldexp_f32, ldexp_f32le, ldexp_f32be,
ldexp_f64, ldexp_f64le, ldexp_f64be,
};
tan_f16 :: proc(θ: f16) -> f16 { return sin(θ)/cos(θ); }
tan_f32 :: proc(θ: f32) -> f32 { return sin(θ)/cos(θ); }
tan_f64 :: proc(θ: f64) -> f64 { return sin(θ)/cos(θ); }
tan :: proc{tan_f16, tan_f32, tan_f64};
log_f16 :: proc(x, base: f16) -> f16 { return ln(x) / ln(base); }
log_f16le :: proc(x, base: f16le) -> f16le { return f16le(log_f16(f16(x), f16(base))); }
log_f16be :: proc(x, base: f16be) -> f16be { return f16be(log_f16(f16(x), f16(base))); }
log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
log_f32le :: proc(x, base: f32le) -> f32le { return f32le(log_f32(f32(x), f32(base))); }
log_f32be :: proc(x, base: f32be) -> f32be { return f32be(log_f32(f32(x), f32(base))); }
log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
log_f64le :: proc(x, base: f64le) -> f64le { return f64le(log_f64(f64(x), f64(base))); }
log_f64be :: proc(x, base: f64be) -> f64be { return f64be(log_f64(f64(x), f64(base))); }
log :: proc{
log_f16, log_f16le, log_f16be,
log_f32, log_f32le, log_f32be,
log_f64, log_f64le, log_f64be,
};
log2_f16 :: proc(x: f16) -> f16 { return ln(x)/LN2; }
log2_f16le :: proc(x: f16le) -> f16le { return f16le(log2_f16(f16(x))); }
log2_f16be :: proc(x: f16be) -> f16be { return f16be(log2_f16(f16(x))); }
log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
log2_f32le :: proc(x: f32le) -> f32le { return f32le(log2_f32(f32(x))); }
log2_f32be :: proc(x: f32be) -> f32be { return f32be(log2_f32(f32(x))); }
log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
log2_f64le :: proc(x: f64le) -> f64le { return f64le(log2_f64(f64(x))); }
log2_f64be :: proc(x: f64be) -> f64be { return f64be(log2_f64(f64(x))); }
log2 :: proc{
log2_f16, log2_f16le, log2_f16be,
log2_f32, log2_f32le, log2_f32be,
log2_f64, log2_f64le, log2_f64be,
};
log10_f16 :: proc(x: f16) -> f16 { return ln(x)/LN10; }
log10_f16le :: proc(x: f16le) -> f16le { return f16le(log10_f16(f16(x))); }
log10_f16be :: proc(x: f16be) -> f16be { return f16be(log10_f16(f16(x))); }
log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
log10_f32le :: proc(x: f32le) -> f32le { return f32le(log10_f32(f32(x))); }
log10_f32be :: proc(x: f32be) -> f32be { return f32be(log10_f32(f32(x))); }
log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
log10_f64le :: proc(x: f64le) -> f64le { return f64le(log10_f64(f64(x))); }
log10_f64be :: proc(x: f64be) -> f64be { return f64be(log10_f64(f64(x))); }
log10 :: proc{
log10_f16, log10_f16le, log10_f16be,
log10_f32, log10_f32le, log10_f32be,
log10_f64, log10_f64le, log10_f64be,
};
tan_f16 :: proc(θ: f16) -> f16 { return sin(θ)/cos(θ); }
tan_f16le :: proc(θ: f16le) -> f16le { return f16le(tan_f16(f16(θ))); }
tan_f16be :: proc(θ: f16be) -> f16be { return f16be(tan_f16(f16(θ))); }
tan_f32 :: proc(θ: f32) -> f32 { return sin(θ)/cos(θ); }
tan_f32le :: proc(θ: f32le) -> f32le { return f32le(tan_f32(f32(θ))); }
tan_f32be :: proc(θ: f32be) -> f32be { return f32be(tan_f32(f32(θ))); }
tan_f64 :: proc(θ: f64) -> f64 { return sin(θ)/cos(θ); }
tan_f64le :: proc(θ: f64le) -> f64le { return f64le(tan_f64(f64(θ))); }
tan_f64be :: proc(θ: f64be) -> f64be { return f64be(tan_f64(f64(θ))); }
tan :: proc{
tan_f16, tan_f16le, tan_f16be,
tan_f32, tan_f32le, tan_f32be,
tan_f64, tan_f64le, tan_f64be,
};
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
saturate :: proc(a: $T) -> (x: T) { return clamp(a, 0, 1); };
unlerp_f16 :: proc(a, b, x: f16) -> (t: f16) { return (x-a)/(b-a); }
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
unlerp :: proc{unlerp_f16, unlerp_f32, unlerp_f64};
unlerp :: proc(a, b, x: $T) -> (t: T) where intrinsics.type_is_float(T), !intrinsics.type_is_array(T) {
return (x-a)/(b-a);
}
remap :: proc(old_value, old_min, old_max, new_min, new_max: $T) -> (x: T) where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) {
old_range := old_max - old_min;
new_range := new_max - new_min;
if old_range == 0 {
return new_range / 2;
}
return ((old_value - old_min) / old_range) * new_range + new_min;
}
wrap :: proc(x, y: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) {
tmp := mod(x, y);
@@ -170,57 +311,105 @@ gain :: proc(t, g: $T) -> T where intrinsics.type_is_numeric(T) {
}
sign_f16 :: proc(x: f16) -> f16 { return f16(int(0 < x) - int(x < 0)); }
sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
sign :: proc{sign_f16, sign_f32, sign_f64};
sign_f16 :: proc(x: f16) -> f16 { return f16(int(0 < x) - int(x < 0)); }
sign_f16le :: proc(x: f16le) -> f16le { return f16le(int(0 < x) - int(x < 0)); }
sign_f16be :: proc(x: f16be) -> f16be { return f16be(int(0 < x) - int(x < 0)); }
sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
sign_f32le :: proc(x: f32le) -> f32le { return f32le(int(0 < x) - int(x < 0)); }
sign_f32be :: proc(x: f32be) -> f32be { return f32be(int(0 < x) - int(x < 0)); }
sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
sign_f64le :: proc(x: f64le) -> f64le { return f64le(int(0 < x) - int(x < 0)); }
sign_f64be :: proc(x: f64be) -> f64be { return f64be(int(0 < x) - int(x < 0)); }
sign :: proc{
sign_f16, sign_f16le, sign_f16be,
sign_f32, sign_f32le, sign_f32be,
sign_f64, sign_f64le, sign_f64be,
};
sign_bit_f16 :: proc(x: f16) -> bool {
sign_bit_f16 :: proc(x: f16) -> bool {
return (transmute(u16)x) & (1<<15) != 0;
}
sign_bit_f32 :: proc(x: f32) -> bool {
sign_bit_f16le :: proc(x: f16le) -> bool { return #force_inline sign_bit_f16(f16(x)); }
sign_bit_f16be :: proc(x: f16be) -> bool { return #force_inline sign_bit_f16(f16(x)); }
sign_bit_f32 :: proc(x: f32) -> bool {
return (transmute(u32)x) & (1<<31) != 0;
}
sign_bit_f64 :: proc(x: f64) -> bool {
sign_bit_f32le :: proc(x: f32le) -> bool { return #force_inline sign_bit_f32(f32(x)); }
sign_bit_f32be :: proc(x: f32be) -> bool { return #force_inline sign_bit_f32(f32(x)); }
sign_bit_f64 :: proc(x: f64) -> bool {
return (transmute(u64)x) & (1<<63) != 0;
}
sign_bit :: proc{sign_bit_f16, sign_bit_f32, sign_bit_f64};
sign_bit_f64le :: proc(x: f64le) -> bool { return #force_inline sign_bit_f64(f64(x)); }
sign_bit_f64be :: proc(x: f64be) -> bool { return #force_inline sign_bit_f64(f64(x)); }
sign_bit :: proc{
sign_bit_f16, sign_bit_f16le, sign_bit_f16be,
sign_bit_f32, sign_bit_f32le, sign_bit_f32be,
sign_bit_f64, sign_bit_f64le, sign_bit_f64be,
};
copy_sign_f16 :: proc(x, y: f16) -> f16 {
copy_sign_f16 :: proc(x, y: f16) -> f16 {
ix := transmute(u16)x;
iy := transmute(u16)y;
ix &= 0x7fff;
ix |= iy & 0x8000;
return transmute(f16)ix;
}
copy_sign_f32 :: proc(x, y: f32) -> f32 {
copy_sign_f16le :: proc(x, y: f16le) -> f16le { return #force_inline f16le(copy_sign_f16(f16(x), f16(y))); }
copy_sign_f16be :: proc(x, y: f16be) -> f16be { return #force_inline f16be(copy_sign_f16(f16(x), f16(y))); }
copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x;
iy := transmute(u32)y;
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32)ix;
}
copy_sign_f64 :: proc(x, y: f64) -> f64 {
copy_sign_f32le :: proc(x, y: f32le) -> f32le { return #force_inline f32le(copy_sign_f32(f32(x), f32(y))); }
copy_sign_f32be :: proc(x, y: f32be) -> f32be { return #force_inline f32be(copy_sign_f32(f32(x), f32(y))); }
copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix := transmute(u64)x;
iy := transmute(u64)y;
ix &= 0x7fff_ffff_ffff_ffff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64)ix;
}
copy_sign :: proc{copy_sign_f16, copy_sign_f32, copy_sign_f64};
copy_sign_f64le :: proc(x, y: f64le) -> f64le { return #force_inline f64le(copy_sign_f64(f64(x), f64(y))); }
copy_sign_f64be :: proc(x, y: f64be) -> f64be { return #force_inline f64be(copy_sign_f64(f64(x), f64(y))); }
copy_sign :: proc{
copy_sign_f16, copy_sign_f16le, copy_sign_f16be,
copy_sign_f32, copy_sign_f32le, copy_sign_f32be,
copy_sign_f64, copy_sign_f64le, copy_sign_f64be,
};
to_radians_f16 :: proc(degrees: f16) -> f16 { return degrees * RAD_PER_DEG; }
to_radians_f16le :: proc(degrees: f16le) -> f16le { return degrees * RAD_PER_DEG; }
to_radians_f16be :: proc(degrees: f16be) -> f16be { return degrees * RAD_PER_DEG; }
to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
to_radians_f32le :: proc(degrees: f32le) -> f32le { return degrees * RAD_PER_DEG; }
to_radians_f32be :: proc(degrees: f32be) -> f32be { return degrees * RAD_PER_DEG; }
to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
to_radians_f64le :: proc(degrees: f64le) -> f64le { return degrees * RAD_PER_DEG; }
to_radians_f64be :: proc(degrees: f64be) -> f64be { return degrees * RAD_PER_DEG; }
to_degrees_f16 :: proc(radians: f16) -> f16 { return radians * DEG_PER_RAD; }
to_degrees_f16le :: proc(radians: f16le) -> f16le { return radians * DEG_PER_RAD; }
to_degrees_f16be :: proc(radians: f16be) -> f16be { return radians * DEG_PER_RAD; }
to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
to_degrees_f32le :: proc(radians: f32le) -> f32le { return radians * DEG_PER_RAD; }
to_degrees_f32be :: proc(radians: f32be) -> f32be { return radians * DEG_PER_RAD; }
to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
to_degrees_f64le :: proc(radians: f64le) -> f64le { return radians * DEG_PER_RAD; }
to_degrees_f64be :: proc(radians: f64be) -> f64be { return radians * DEG_PER_RAD; }
to_radians :: proc{
to_radians_f16, to_radians_f16le, to_radians_f16be,
to_radians_f32, to_radians_f32le, to_radians_f32be,
to_radians_f64, to_radians_f64le, to_radians_f64be,
};
to_degrees :: proc{
to_degrees_f16, to_degrees_f16le, to_degrees_f16be,
to_degrees_f32, to_degrees_f32le, to_degrees_f32be,
to_degrees_f64, to_degrees_f64le, to_degrees_f64be,
};
to_radians_f16 :: proc(degrees: f16) -> f16 { return degrees * RAD_PER_DEG; }
to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
to_degrees_f16 :: proc(radians: f16) -> f16 { return radians * DEG_PER_RAD; }
to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
to_radians :: proc{to_radians_f16, to_radians_f32, to_radians_f64};
to_degrees :: proc{to_degrees_f16, to_degrees_f32, to_degrees_f64};
trunc_f16 :: proc(x: f16) -> f16 {
trunc_f16 :: proc(x: f16) -> f16 {
trunc_internal :: proc(f: f16) -> f16 {
mask :: 0x1f;
shift :: 16 - 6;
@@ -249,8 +438,10 @@ trunc_f16 :: proc(x: f16) -> f16 {
}
return trunc_internal(x);
}
trunc_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(trunc_f16(f16(x))); }
trunc_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(trunc_f16(f16(x))); }
trunc_f32 :: proc(x: f32) -> f32 {
trunc_f32 :: proc(x: f32) -> f32 {
trunc_internal :: proc(f: f32) -> f32 {
mask :: 0xff;
shift :: 32 - 9;
@@ -279,8 +470,10 @@ trunc_f32 :: proc(x: f32) -> f32 {
}
return trunc_internal(x);
}
trunc_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(trunc_f32(f32(x))); }
trunc_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(trunc_f32(f32(x))); }
trunc_f64 :: proc(x: f64) -> f64 {
trunc_f64 :: proc(x: f64) -> f64 {
trunc_internal :: proc(f: f64) -> f64 {
mask :: 0x7ff;
shift :: 64 - 12;
@@ -309,27 +502,68 @@ trunc_f64 :: proc(x: f64) -> f64 {
}
return trunc_internal(x);
}
trunc_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))); }
trunc_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))); }
trunc :: proc{
trunc_f16, trunc_f16le, trunc_f16be,
trunc_f32, trunc_f32le, trunc_f32be,
trunc_f64, trunc_f64le, trunc_f64be,
};
trunc :: proc{trunc_f16, trunc_f32, trunc_f64};
round_f16 :: proc(x: f16) -> f16 {
round_f16 :: proc(x: f16) -> f16 {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f32 :: proc(x: f32) -> f32 {
round_f16le :: proc(x: f16le) -> f16le {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f64 :: proc(x: f64) -> f64 {
round_f16be :: proc(x: f16be) -> f16be {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round :: proc{round_f16, round_f32, round_f64};
round_f32 :: proc(x: f32) -> f32 {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f32le :: proc(x: f32le) -> f32le {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f32be :: proc(x: f32be) -> f32be {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f64 :: proc(x: f64) -> f64 {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f64le :: proc(x: f64le) -> f64le {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round_f64be :: proc(x: f64be) -> f64be {
return ceil(x - 0.5) if x < 0 else floor(x + 0.5);
}
round :: proc{
round_f16, round_f16le, round_f16be,
round_f32, round_f32le, round_f32be,
round_f64, round_f64le, round_f64be,
};
ceil_f16 :: proc(x: f16) -> f16 { return -floor(-x); }
ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
ceil :: proc{ceil_f16, ceil_f32, ceil_f64};
ceil_f16 :: proc(x: f16) -> f16 { return -floor(-x); }
ceil_f16le :: proc(x: f16le) -> f16le { return -floor(-x); }
ceil_f16be :: proc(x: f16be) -> f16be { return -floor(-x); }
floor_f16 :: proc(x: f16) -> f16 {
ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
ceil_f32le :: proc(x: f32le) -> f32le { return -floor(-x); }
ceil_f32be :: proc(x: f32be) -> f32be { return -floor(-x); }
ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
ceil_f64le :: proc(x: f64le) -> f64le { return -floor(-x); }
ceil_f64be :: proc(x: f64be) -> f64be { return -floor(-x); }
ceil :: proc{
ceil_f16, ceil_f16le, ceil_f16be,
ceil_f32, ceil_f32le, ceil_f32be,
ceil_f64, ceil_f64le, ceil_f64be,
};
floor_f16 :: proc(x: f16) -> f16 {
if x == 0 || is_nan(x) || is_inf(x) {
return x;
}
@@ -343,7 +577,9 @@ floor_f16 :: proc(x: f16) -> f16 {
d, _ := modf(x);
return d;
}
floor_f32 :: proc(x: f32) -> f32 {
floor_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(floor_f16(f16(x))); }
floor_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(floor_f16(f16(x))); }
floor_f32 :: proc(x: f32) -> f32 {
if x == 0 || is_nan(x) || is_inf(x) {
return x;
}
@@ -357,7 +593,9 @@ floor_f32 :: proc(x: f32) -> f32 {
d, _ := modf(x);
return d;
}
floor_f64 :: proc(x: f64) -> f64 {
floor_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(floor_f32(f32(x))); }
floor_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(floor_f32(f32(x))); }
floor_f64 :: proc(x: f64) -> f64 {
if x == 0 || is_nan(x) || is_inf(x) {
return x;
}
@@ -371,7 +609,13 @@ floor_f64 :: proc(x: f64) -> f64 {
d, _ := modf(x);
return d;
}
floor :: proc{floor_f16, floor_f32, floor_f64};
floor_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(floor_f64(f64(x))); }
floor_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(floor_f64(f64(x))); }
floor :: proc{
floor_f16, floor_f16le, floor_f16be,
floor_f32, floor_f32le, floor_f32be,
floor_f64, floor_f64le, floor_f64be,
};
floor_div :: proc(x, y: $T) -> T
@@ -393,7 +637,7 @@ floor_mod :: proc(x, y: $T) -> T
return r;
}
modf_f16 :: proc(x: f16) -> (int: f16, frac: f16) {
modf_f16 :: proc(x: f16) -> (int: f16, frac: f16) {
shift :: 16 - 5 - 1;
mask :: 0x1f;
bias :: 15;
@@ -419,7 +663,15 @@ modf_f16 :: proc(x: f16) -> (int: f16, frac: f16) {
frac = x - int;
return;
}
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
modf_f16le :: proc(x: f16le) -> (int: f16le, frac: f16le) {
i, f := #force_inline modf_f16(f16(x));
return f16le(i), f16le(f);
}
modf_f16be :: proc(x: f16be) -> (int: f16be, frac: f16be) {
i, f := #force_inline modf_f16(f16(x));
return f16be(i), f16be(f);
}
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
shift :: 32 - 8 - 1;
mask :: 0xff;
bias :: 127;
@@ -445,7 +697,15 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
frac = x - int;
return;
}
modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
modf_f32le :: proc(x: f32le) -> (int: f32le, frac: f32le) {
i, f := #force_inline modf_f32(f32(x));
return f32le(i), f32le(f);
}
modf_f32be :: proc(x: f32be) -> (int: f32be, frac: f32be) {
i, f := #force_inline modf_f32(f32(x));
return f32be(i), f32be(f);
}
modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
shift :: 64 - 11 - 1;
mask :: 0x7ff;
bias :: 1023;
@@ -471,10 +731,22 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
frac = x - int;
return;
}
modf :: proc{modf_f16, modf_f32, modf_f64};
modf_f64le :: proc(x: f64le) -> (int: f64le, frac: f64le) {
i, f := #force_inline modf_f64(f64(x));
return f64le(i), f64le(f);
}
modf_f64be :: proc(x: f64be) -> (int: f64be, frac: f64be) {
i, f := #force_inline modf_f64(f64(x));
return f64be(i), f64be(f);
}
modf :: proc{
modf_f16, modf_f16le, modf_f16be,
modf_f32, modf_f32le, modf_f32be,
modf_f64, modf_f64le, modf_f64be,
};
split_decimal :: modf;
mod_f16 :: proc(x, y: f16) -> (n: f16) {
mod_f16 :: proc(x, y: f16) -> (n: f16) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
@@ -482,7 +754,9 @@ mod_f16 :: proc(x, y: f16) -> (n: f16) {
}
return copy_sign(n, x);
}
mod_f32 :: proc(x, y: f32) -> (n: f32) {
mod_f16le :: proc(x, y: f16le) -> (n: f16le) { return #force_inline f16le(mod_f16(f16(x), f16(y))); }
mod_f16be :: proc(x, y: f16be) -> (n: f16be) { return #force_inline f16be(mod_f16(f16(x), f16(y))); }
mod_f32 :: proc(x, y: f32) -> (n: f32) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
@@ -490,7 +764,9 @@ mod_f32 :: proc(x, y: f32) -> (n: f32) {
}
return copy_sign(n, x);
}
mod_f64 :: proc(x, y: f64) -> (n: f64) {
mod_f32le :: proc(x, y: f32le) -> (n: f32le) { return #force_inline f32le(mod_f32(f32(x), f32(y))); }
mod_f32be :: proc(x, y: f32be) -> (n: f32be) { return #force_inline f32be(mod_f32(f32(x), f32(y))); }
mod_f64 :: proc(x, y: f64) -> (n: f64) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
@@ -498,14 +774,28 @@ mod_f64 :: proc(x, y: f64) -> (n: f64) {
}
return copy_sign(n, x);
}
mod :: proc{mod_f16, mod_f32, mod_f64};
remainder_f16 :: proc(x, y: f16) -> f16 { return x - round(x/y) * y; }
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
remainder :: proc{remainder_f16, remainder_f32, remainder_f64};
mod_f64le :: proc(x, y: f64le) -> (n: f64le) { return #force_inline f64le(mod_f64(f64(x), f64(y))); }
mod_f64be :: proc(x, y: f64be) -> (n: f64be) { return #force_inline f64be(mod_f64(f64(x), f64(y))); }
mod :: proc{
mod_f16, mod_f16le, mod_f16be,
mod_f32, mod_f32le, mod_f32be,
mod_f64, mod_f64le, mod_f64be,
};
remainder_f16 :: proc(x, y: f16 ) -> f16 { return x - round(x/y) * y; }
remainder_f16le :: proc(x, y: f16le) -> f16le { return x - round(x/y) * y; }
remainder_f16be :: proc(x, y: f16be) -> f16be { return x - round(x/y) * y; }
remainder_f32 :: proc(x, y: f32 ) -> f32 { return x - round(x/y) * y; }
remainder_f32le :: proc(x, y: f32le) -> f32le { return x - round(x/y) * y; }
remainder_f32be :: proc(x, y: f32be) -> f32be { return x - round(x/y) * y; }
remainder_f64 :: proc(x, y: f64 ) -> f64 { return x - round(x/y) * y; }
remainder_f64le :: proc(x, y: f64le) -> f64le { return x - round(x/y) * y; }
remainder_f64be :: proc(x, y: f64be) -> f64be { return x - round(x/y) * y; }
remainder :: proc{
remainder_f16, remainder_f16le, remainder_f16be,
remainder_f32, remainder_f32le, remainder_f32be,
remainder_f64, remainder_f64le, remainder_f64be,
};
gcd :: proc(x, y: $T) -> T
where intrinsics.type_is_ordered_numeric(T) {
@@ -522,14 +812,30 @@ lcm :: proc(x, y: $T) -> T
return x / gcd(x, y) * y;
}
frexp_f16 :: proc(x: f16) -> (significand: f16, exponent: int) {
frexp_f16 :: proc(x: f16) -> (significand: f16, exponent: int) {
f, e := frexp_f64(f64(x));
return f16(f), e;
}
frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) {
frexp_f16le :: proc(x: f16le) -> (significand: f16le, exponent: int) {
f, e := frexp_f64(f64(x));
return f16le(f), e;
}
frexp_f16be :: proc(x: f16be) -> (significand: f16be, exponent: int) {
f, e := frexp_f64(f64(x));
return f16be(f), e;
}
frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) {
f, e := frexp_f64(f64(x));
return f32(f), e;
}
frexp_f32le :: proc(x: f32le) -> (significand: f32le, exponent: int) {
f, e := frexp_f64(f64(x));
return f32le(f), e;
}
frexp_f32be :: proc(x: f32be) -> (significand: f32be, exponent: int) {
f, e := frexp_f64(f64(x));
return f32be(f), e;
}
frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) {
switch {
case x == 0:
@@ -550,7 +856,19 @@ frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) {
}
return;
}
frexp :: proc{frexp_f16, frexp_f32, frexp_f64};
frexp_f64le :: proc(x: f64le) -> (significand: f64le, exponent: int) {
f, e := frexp_f64(f64(x));
return f64le(f), e;
}
frexp_f64be :: proc(x: f64be) -> (significand: f64be, exponent: int) {
f, e := frexp_f64(f64(x));
return f64be(f), e;
}
frexp :: proc{
frexp_f16, frexp_f16le, frexp_f16be,
frexp_f32, frexp_f32le, frexp_f32be,
frexp_f64, frexp_f64le, frexp_f64be,
};
@@ -616,7 +934,7 @@ factorial :: proc(n: int) -> int {
return table[n];
}
classify_f16 :: proc(x: f16) -> Float_Class {
classify_f16 :: proc(x: f16) -> Float_Class {
switch {
case x == 0:
i := transmute(i16)x;
@@ -640,7 +958,9 @@ classify_f16 :: proc(x: f16) -> Float_Class {
}
return .Normal;
}
classify_f32 :: proc(x: f32) -> Float_Class {
classify_f16le :: proc(x: f16le) -> Float_Class { return #force_inline classify_f16(f16(x)); }
classify_f16be :: proc(x: f16be) -> Float_Class { return #force_inline classify_f16(f16(x)); }
classify_f32 :: proc(x: f32) -> Float_Class {
switch {
case x == 0:
i := transmute(i32)x;
@@ -664,7 +984,9 @@ classify_f32 :: proc(x: f32) -> Float_Class {
}
return .Normal;
}
classify_f64 :: proc(x: f64) -> Float_Class {
classify_f32le :: proc(x: f32le) -> Float_Class { return #force_inline classify_f32(f32(x)); }
classify_f32be :: proc(x: f32be) -> Float_Class { return #force_inline classify_f32(f32(x)); }
classify_f64 :: proc(x: f64) -> Float_Class {
switch {
case x == 0:
i := transmute(i64)x;
@@ -687,13 +1009,28 @@ classify_f64 :: proc(x: f64) -> Float_Class {
}
return .Normal;
}
classify :: proc{classify_f16, classify_f32, classify_f64};
is_nan_f16 :: proc(x: f16) -> bool { return classify(x) == .NaN; }
is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; }
is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; }
is_nan :: proc{is_nan_f16, is_nan_f32, is_nan_f64};
classify_f64le :: proc(x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)); }
classify_f64be :: proc(x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)); }
classify :: proc{
classify_f16, classify_f16le, classify_f16be,
classify_f32, classify_f32le, classify_f32be,
classify_f64, classify_f64le, classify_f64be,
};
is_nan_f16 :: proc(x: f16) -> bool { return classify(x) == .NaN; }
is_nan_f16le :: proc(x: f16le) -> bool { return classify(x) == .NaN; }
is_nan_f16be :: proc(x: f16be) -> bool { return classify(x) == .NaN; }
is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; }
is_nan_f32le :: proc(x: f32le) -> bool { return classify(x) == .NaN; }
is_nan_f32be :: proc(x: f32be) -> bool { return classify(x) == .NaN; }
is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; }
is_nan_f64le :: proc(x: f64le) -> bool { return classify(x) == .NaN; }
is_nan_f64be :: proc(x: f64be) -> bool { return classify(x) == .NaN; }
is_nan :: proc{
is_nan_f16, is_nan_f16le, is_nan_f16be,
is_nan_f32, is_nan_f32le, is_nan_f32be,
is_nan_f64, is_nan_f64le, is_nan_f64be,
};
// is_inf reports whether f is an infinity, according to sign.
// If sign > 0, is_inf reports whether f is positive infinity.
@@ -709,6 +1046,13 @@ is_inf_f16 :: proc(x: f16, sign: int = 0) -> bool {
}
return class == .Inf || class == .Neg_Inf;
}
is_inf_f16le :: proc(x: f16le, sign: int = 0) -> bool {
return #force_inline is_inf_f16(f16(x), sign);
}
is_inf_f16be :: proc(x: f16be, sign: int = 0) -> bool {
return #force_inline is_inf_f16(f16(x), sign);
}
is_inf_f32 :: proc(x: f32, sign: int = 0) -> bool {
class := classify(abs(x));
switch {
@@ -719,6 +1063,13 @@ is_inf_f32 :: proc(x: f32, sign: int = 0) -> bool {
}
return class == .Inf || class == .Neg_Inf;
}
is_inf_f32le :: proc(x: f32le, sign: int = 0) -> bool {
return #force_inline is_inf_f32(f32(x), sign);
}
is_inf_f32be :: proc(x: f32be, sign: int = 0) -> bool {
return #force_inline is_inf_f32(f32(x), sign);
}
is_inf_f64 :: proc(x: f64, sign: int = 0) -> bool {
class := classify(abs(x));
switch {
@@ -729,16 +1080,37 @@ is_inf_f64 :: proc(x: f64, sign: int = 0) -> bool {
}
return class == .Inf || class == .Neg_Inf;
}
is_inf :: proc{is_inf_f16, is_inf_f32, is_inf_f64};
inf_f16 :: proc(sign: int) -> f16 {
return f16(inf_f16(sign));
is_inf_f64le :: proc(x: f64le, sign: int = 0) -> bool {
return #force_inline is_inf_f64(f64(x), sign);
}
inf_f32 :: proc(sign: int) -> f32 {
is_inf_f64be :: proc(x: f64be, sign: int = 0) -> bool {
return #force_inline is_inf_f64(f64(x), sign);
}
is_inf :: proc{
is_inf_f16, is_inf_f16le, is_inf_f16be,
is_inf_f32, is_inf_f32le, is_inf_f32be,
is_inf_f64, is_inf_f64le, is_inf_f64be,
};
inf_f16 :: proc(sign: int) -> f16 {
return f16(inf_f64(sign));
}
inf_f16le :: proc(sign: int) -> f16le {
return f16le(inf_f64(sign));
}
inf_f16be :: proc(sign: int) -> f16be {
return f16be(inf_f64(sign));
}
inf_f32 :: proc(sign: int) -> f32 {
return f32(inf_f64(sign));
}
inf_f64 :: proc(sign: int) -> f64 {
inf_f32le :: proc(sign: int) -> f32le {
return f32le(inf_f64(sign));
}
inf_f32be :: proc(sign: int) -> f32be {
return f32be(inf_f64(sign));
}
inf_f64 :: proc(sign: int) -> f64 {
v: u64;
if sign >= 0 {
v = 0x7ff00000_00000000;
@@ -747,19 +1119,41 @@ inf_f64 :: proc(sign: int) -> f64 {
}
return transmute(f64)v;
}
inf_f64le :: proc(sign: int) -> f64le {
return f64le(inf_f64(sign));
}
inf_f64be :: proc(sign: int) -> f64be {
return f64be(inf_f64(sign));
}
nan_f16 :: proc() -> f16 {
nan_f16 :: proc() -> f16 {
return f16(nan_f64());
}
nan_f32 :: proc() -> f32 {
nan_f16le :: proc() -> f16le {
return f16le(nan_f64());
}
nan_f16be :: proc() -> f16be {
return f16be(nan_f64());
}
nan_f32 :: proc() -> f32 {
return f32(nan_f64());
}
nan_f64 :: proc() -> f64 {
nan_f32le :: proc() -> f32le {
return f32le(nan_f64());
}
nan_f32be :: proc() -> f32be {
return f32be(nan_f64());
}
nan_f64 :: proc() -> f64 {
v: u64 = 0x7ff80000_00000001;
return transmute(f64)v;
}
nan_f64le :: proc() -> f64le {
return f64le(nan_f64());
}
nan_f64be :: proc() -> f64be {
return f64be(nan_f64());
}
is_power_of_two :: proc(x: int) -> bool {
return x > 0 && (x & (x-1)) == 0;
@@ -816,14 +1210,30 @@ cumsum :: proc(dst, src: $T/[]$E) -> T
}
atan2_f16 :: proc(y, x: f16) -> f16 {
atan2_f16 :: proc(y, x: f16) -> f16 {
// TODO(bill): Better atan2_f16
return f16(atan2_f64(f64(y), f64(x)));
}
atan2_f32 :: proc(y, x: f32) -> f32 {
atan2_f16le :: proc(y, x: f16le) -> f16le {
// TODO(bill): Better atan2_f16
return f16le(atan2_f64(f64(y), f64(x)));
}
atan2_f16be :: proc(y, x: f16be) -> f16be {
// TODO(bill): Better atan2_f16
return f16be(atan2_f64(f64(y), f64(x)));
}
atan2_f32 :: proc(y, x: f32) -> f32 {
// TODO(bill): Better atan2_f32
return f32(atan2_f64(f64(y), f64(x)));
}
atan2_f32le :: proc(y, x: f32le) -> f32le {
// TODO(bill): Better atan2_f32
return f32le(atan2_f64(f64(y), f64(x)));
}
atan2_f32be :: proc(y, x: f32be) -> f32be {
// TODO(bill): Better atan2_f32
return f32be(atan2_f64(f64(y), f64(x)));
}
atan2_f64 :: proc(y, x: f64) -> f64 {
// TODO(bill): Faster atan2_f64 if possible
@@ -910,80 +1320,45 @@ atan2_f64 :: proc(y, x: f64) -> f64 {
}
return q;
}
atan2_f64le :: proc(y, x: f64le) -> f64le {
// TODO(bill): Better atan2_f32
return f64le(atan2_f64(f64(y), f64(x)));
}
atan2_f64be :: proc(y, x: f64be) -> f64be {
// TODO(bill): Better atan2_f32
return f64be(atan2_f64(f64(y), f64(x)));
}
atan2 :: proc{
atan2_f16, atan2_f16le, atan2_f16be,
atan2_f32, atan2_f32le, atan2_f32be,
atan2_f64, atan2_f64le, atan2_f64be,
};
atan2 :: proc{atan2_f16, atan2_f32, atan2_f64};
atan :: proc(x: $T) -> T where intrinsics.type_is_float(T) {
return atan2(x, 1);
}
atan_f16 :: proc(x: f16) -> f16 {
return atan2_f16(x, 1);
asin :: proc(x: $T) -> T where intrinsics.type_is_float(T) {
return atan2(x, 1 + sqrt(1 - x*x));
}
atan_f32 :: proc(x: f32) -> f32 {
return atan2_f32(x, 1);
}
atan_f64 :: proc(x: f64) -> f64 {
return atan2_f64(x, 1);
}
atan :: proc{atan_f16, atan_f32, atan_f64};
asin_f16 :: proc(x: f16) -> f16 {
return atan2_f16(x, 1 + sqrt_f16(1 - x*x));
acos :: proc(x: $T) -> T where intrinsics.type_is_float(T) {
return 2 * atan2(sqrt(1 - x), sqrt(1 + x));
}
asin_f32 :: proc(x: f32) -> f32 {
return atan2_f32(x, 1 + sqrt_f32(1 - x*x));
}
asin_f64 :: proc(x: f64) -> f64 {
return atan2_f64(x, 1 + sqrt_f64(1 - x*x));
}
asin :: proc{asin_f16, asin_f32, asin_f64};
acos_f16 :: proc(x: f16) -> f16 {
return 2 * atan2_f16(sqrt_f16(1 - x), sqrt_f16(1 + x));
}
acos_f32 :: proc(x: f32) -> f32 {
return 2 * atan2_f32(sqrt_f32(1 - x), sqrt_f32(1 + x));
}
acos_f64 :: proc(x: f64) -> f64 {
return 2 * atan2_f64(sqrt_f64(1 - x), sqrt_f64(1 + x));
}
acos :: proc{acos_f16, acos_f32, acos_f64};
sinh_f16 :: proc(x: f16) -> f16 {
sinh :: proc(x: $T) -> T where intrinsics.type_is_float(T) {
return (exp(x) - exp(-x))*0.5;
}
sinh_f32 :: proc(x: f32) -> f32 {
return (exp(x) - exp(-x))*0.5;
}
sinh_f64 :: proc(x: f64) -> f64 {
return (exp(x) - exp(-x))*0.5;
}
sinh :: proc{sinh_f16, sinh_f32, sinh_f64};
cosh_f16 :: proc(x: f16) -> f16 {
cosh :: proc(x: $T) -> T where intrinsics.type_is_float(T) {
return (exp(x) + exp(-x))*0.5;
}
cosh_f32 :: proc(x: f32) -> f32 {
return (exp(x) + exp(-x))*0.5;
}
cosh_f64 :: proc(x: f64) -> f64 {
return (exp(x) + exp(-x))*0.5;
}
cosh :: proc{cosh_f16, cosh_f32, cosh_f64};
tanh_f16 :: proc(x: f16) -> f16 {
tanh :: proc(x: $T) -> T where intrinsics.type_is_float(T) {
t := exp(2*x);
return (t - 1) / (t + 1);
}
tanh_f32 :: proc(x: f32) -> f32 {
t := exp(2*x);
return (t - 1) / (t + 1);
}
tanh_f64 :: proc(x: f64) -> f64 {
t := exp(2*x);
return (t - 1) / (t + 1);
}
tanh :: proc{tanh_f16, tanh_f32, tanh_f64};
F16_DIG :: 3;
F16_EPSILON :: 0.00097656;
+2 -2
View File
@@ -6,9 +6,9 @@ Rand :: struct {
}
@(private, static)
@(private)
_GLOBAL_SEED_DATA := 1234567890;
@(private, static)
@(private)
global_rand := create(u64(uintptr(&_GLOBAL_SEED_DATA)));
set_global_seed :: proc(seed: u64) {
+1 -1
View File
@@ -22,7 +22,7 @@ Allocator_Mode_Set :: distinct bit_set[Allocator_Mode];
Allocator_Query_Info :: runtime.Allocator_Query_Info;
/*
Allocator_Query_Info :: struct {
pointer: Maybe(rawptr),
pointer: rawptr,
size: Maybe(int),
alignment: Maybe(int),
}
+1 -1
View File
@@ -919,7 +919,7 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
// Small_Allocator primary allocates memory from its local buffer of size BUFFER_SIZE
// If that buffer's memory is exhausted, it will use the backing allocator (a scratch allocator is recommended)
// Memory allocated with Small_Allocator cannot be freed individually using 'free' and must be freed using 'free_all'
Small_Allocator :: struct(BUFFER_SIZE: int)
Small_Allocator :: struct($BUFFER_SIZE: int)
where
BUFFER_SIZE >= 2*size_of(uintptr),
BUFFER_SIZE & (BUFFER_SIZE-1) == 0 {
+1
View File
@@ -142,6 +142,7 @@ slice_ptr :: proc(ptr: ^$T, len: int) -> []T {
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte {
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)};
}
@(deprecated="use byte_slice")
slice_ptr_to_bytes :: proc(data: rawptr, len: int) -> []byte {
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)};
}
+7 -11
View File
@@ -16,16 +16,12 @@ Proc_Inlining :: enum u32 {
No_Inline = 2,
}
Proc_Calling_Convention :: enum i32 {
Invalid = 0,
Odin,
Contextless,
C_Decl,
Std_Call,
Fast_Call,
None,
Foreign_Block_Default = -1,
Proc_Calling_Convention_Extra :: enum i32 {
Foreign_Block_Default,
}
Proc_Calling_Convention :: union {
string,
Proc_Calling_Convention_Extra,
}
Node_State_Flag :: enum {
@@ -69,7 +65,7 @@ File :: struct {
pkg: ^Package,
fullpath: string,
src: []byte,
src: string,
docs: ^Comment_Group,
+84 -23
View File
@@ -28,11 +28,11 @@ Magic_String :: "odindoc\x00";
Header_Base :: struct {
magic: [8]byte,
_: u32le,
_: u32le, // padding
version: Version_Type,
total_size: u32le,
header_size: u32le,
hash: u32le,
total_size: u32le, // in bytes
header_size: u32le, // in bytes
hash: u32le, // hash of the data after the header (header_size)
}
Header :: struct {
@@ -95,16 +95,17 @@ Entity_Flag :: enum u32le {
Foreign = 0,
Export = 1,
Param_Using = 2,
Param_Const = 3,
Param_Auto_Cast = 4,
Param_Ellipsis = 5,
Param_CVararg = 6,
Param_No_Alias = 7,
Param_Using = 2, // using
Param_Const = 3, // #const
Param_Auto_Cast = 4, // auto_cast
Param_Ellipsis = 5, // Variadic parameter
Param_CVararg = 6, // #c_vararg
Param_No_Alias = 7, // #no_alias
Type_Alias = 8,
Var_Thread_Local = 9,
Var_Static = 10,
}
Entity_Flags :: distinct bit_set[Entity_Flag; u32le];
@@ -116,14 +117,25 @@ Entity :: struct {
name: String,
type: Type_Index,
init_string: String,
_: u32le,
_: u32le, // reserved for init
comment: String,
docs: String,
// May used by:
// .Variable
// .Procedure
foreign_library: Entity_Index,
// May used by:
// .Variable
// .Procedure
link_name: String,
attributes: Array(Attribute),
grouped_entities: Array(Entity_Index), // Procedure Groups
where_clauses: Array(String), // Procedures
// Used by: .Proc_Group
grouped_entities: Array(Entity_Index),
// May used by: .Procedure
where_clauses: Array(String),
}
Attribute :: struct {
@@ -159,21 +171,70 @@ Type_Kind :: enum u32le {
Type_Elems_Cap :: 4;
Type :: struct {
kind: Type_Kind,
flags: u32le, // Type_Kind specific
name: String,
kind: Type_Kind,
// Type_Kind specific used by some types
// Underlying flag types:
// .Basic - Type_Flags_Basic
// .Struct - Type_Flags_Struct
// .Union - Type_Flags_Union
// .Proc - Type_Flags_Proc
// .Bit_Set - Type_Flags_Bit_Set
flags: u32le,
// Used by:
// .Basic
// .Named
// .Generic
name: String,
// Used By: .Struct, .Union
custom_align: String,
// Used by some types
// Used by:
// .Array - 1 count: 0=len
// .Enumerated_Array - 1 count: 0=len
// .SOA_Struct_Fixed - 1 count: 0=len
// .Bit_Set - 2 count: 0=lower, 1=upper
// .Simd_Vector - 1 count: 0=len
elem_count_len: u32le,
elem_counts: [Type_Elems_Cap]i64le,
// Each of these is esed by some types, not all
calling_convention: String, // Procedures
types: Array(Type_Index),
entities: Array(Entity_Index),
polymorphic_params: Type_Index, // Struct, Union
where_clauses: Array(String), // Struct, Union
// Used by: .Procedures
// blank implies the "odin" calling convention
calling_convention: String,
// Used by:
// .Named - 1 type: 0=base type
// .Generic - <1 type: 0=specialization
// .Pointer - 1 type: 0=element
// .Array - 1 type: 0=element
// .Enumerated_Array - 2 types: 0=index and 1=element
// .Slice - 1 type: 0=element
// .Dynamic_Array - 1 type: 0=element
// .Map - 2 types: 0=key, 1=value
// .SOA_Struct_Fixed - 1 type: underlying SOA struct element
// .SOA_Struct_Slice - 1 type: underlying SOA struct element
// .SOA_Struct_Dynamic - 1 type: underlying SOA struct element
// .Union - 0+ types: variants
// .Enum - <1 type: 0=base type
// .Proc - 2 types: 0=parameters, 1=results
// .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set)
// .Simd_Vector - 1 type: 0=element
// .Relative_Pointer - 2 types: 0=pointer type, 1=base integer
// .Relative_Slice - 2 types: 0=slice type, 1=base integer
types: Array(Type_Index),
// Used by:
// .Named - 1 field for the definition
// .Struct - fields
// .Enum - fields
// .Tuple - parameters (procedures only)
entities: Array(Entity_Index),
// Used By: .Struct, .Union
polymorphic_params: Type_Index,
// Used By: .Struct, .Union
where_clauses: Array(String),
}
Type_Flags_Basic :: distinct bit_set[Type_Flag_Basic; u32le];
+41
View File
@@ -0,0 +1,41 @@
package odin_format
import "core:odin/printer"
import "core:odin/parser"
import "core:odin/ast"
default_style := printer.default_style;
simplify :: proc(file: ^ast.File) {
}
format :: proc(filepath: string, source: string, config: printer.Config, parser_flags := parser.Flags{}, allocator := context.allocator) -> (string, bool) {
config := config;
pkg := ast.Package {
kind = .Normal,
};
file := ast.File {
pkg = &pkg,
src = source,
fullpath = filepath,
};
config.newline_limit = clamp(config.newline_limit, 0, 16);
config.spaces = clamp(config.spaces, 1, 16);
config.align_length_break = clamp(config.align_length_break, 0, 64);
p := parser.default_parser(parser_flags);
ok := parser.parse_file(&p, &file);
if !ok || file.syntax_error_count > 0 {
return {}, false;
}
prnt := printer.make_printer(config, allocator);
return printer.print(&prnt, &file), true;
}
+1 -1
View File
@@ -39,7 +39,7 @@ collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) {
}
file := ast.new(ast.File, NO_POS, NO_POS);
file.pkg = pkg;
file.src = src;
file.src = string(src);
file.fullpath = fullpath;
pkg.files[fullpath] = file;
}
+79 -50
View File
@@ -8,10 +8,21 @@ import "core:fmt"
Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any);
Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any);
Flag :: enum u32 {
Optional_Semicolons,
}
Flags :: distinct bit_set[Flag; u32];
Parser :: struct {
file: ^ast.File,
tok: tokenizer.Tokenizer,
// If .Optional_Semicolons is true, semicolons are completely as statement terminators
// different to .Insert_Semicolon in tok.flags
flags: Flags,
warn: Warning_Handler,
err: Error_Handler,
@@ -100,8 +111,9 @@ end_pos :: proc(tok: tokenizer.Token) -> tokenizer.Pos {
return pos;
}
default_parser :: proc() -> Parser {
default_parser :: proc(flags := Flags{}) -> Parser {
return Parser {
flags = flags,
err = default_error_handler,
warn = default_warning_handler,
};
@@ -128,6 +140,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
p.line_comment = nil;
}
if .Optional_Semicolons in p.flags {
p.tok.flags += {.Insert_Semicolon};
}
p.file = file;
tokenizer.init(&p.tok, file.src, file.fullpath, p.err);
if p.tok.ch <= 0 {
@@ -400,6 +416,11 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
if node == nil {
return false;
}
if .Optional_Semicolons in p.flags {
return true;
}
switch n in node.derived {
case ast.Empty_Stmt, ast.Block_Stmt:
return true;
@@ -439,14 +460,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
return false;
}
expect_semicolon_newline_error :: proc(p: ^Parser, token: tokenizer.Token, s: ^ast.Node) {
if .Optional_Semicolons not_in p.flags && .Insert_Semicolon in p.tok.flags && token.text == "\n" {
#partial switch token.kind {
case .Close_Brace:
case .Close_Paren:
case .Else:
return;
}
if is_semicolon_optional_for_node(p, s) {
return;
}
tok := token;
tok.pos.column -= 1;
error(p, tok.pos, "expected ';', got newline");
}
}
expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool {
if allow_token(p, .Semicolon) {
expect_semicolon_newline_error(p, p.prev_tok, node);
return true;
}
prev := p.prev_tok;
if prev.kind == .Semicolon {
expect_semicolon_newline_error(p, p.prev_tok, node);
return true;
}
@@ -615,7 +656,7 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
cond = parse_expr(p, false);
} else {
init = parse_simple_stmt(p, nil);
if allow_token(p, .Semicolon) {
if parse_control_statement_semicolon_separator(p) {
cond = parse_expr(p, false);
} else {
cond = convert_stmt_to_expr(p, init, "boolean expression");
@@ -668,6 +709,18 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
return if_stmt;
}
parse_control_statement_semicolon_separator :: proc(p: ^Parser) -> bool {
tok := peek_token(p);
if tok.kind != .Open_Brace {
return allow_token(p, .Semicolon);
}
if tok.text == ";" {
return allow_token(p, .Semicolon);
}
return false;
}
parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if p.curr_proc == nil {
error(p, p.curr_tok.pos, "you cannot use a for statement in the file scope");
@@ -716,7 +769,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
}
}
if !is_range && allow_token(p, .Semicolon) {
if !is_range && parse_control_statement_semicolon_separator(p) {
init = cond;
cond = nil;
if p.curr_tok.kind != .Semicolon {
@@ -820,7 +873,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In});
if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
is_type_switch = true;
} else if allow_token(p, .Semicolon) {
} else if parse_control_statement_semicolon_separator(p) {
init = tag;
tag = nil;
if p.curr_tok.kind != .Open_Brace {
@@ -831,6 +884,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
}
skip_possible_newline(p);
open := expect_token(p, .Open_Brace);
for p.curr_tok.kind == .Case {
@@ -958,6 +1012,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl
defer p.in_foreign_block = prev_in_foreign_block;
p.in_foreign_block = true;
skip_possible_newline_for_literal(p);
open := expect_token(p, .Open_Brace);
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
decl := parse_foreign_block_decl(p);
@@ -1287,7 +1342,7 @@ token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
#partial switch kind {
case .Question, .If, .When:
return 1;
case .Ellipsis, .Range_Half:
case .Ellipsis, .Range_Half, .Range_Full:
if !p.allow_range {
return 0;
}
@@ -1884,24 +1939,12 @@ parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) {
string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention {
if s[0] != '"' && s[0] != '`' {
return .Invalid;
return nil;
}
switch s[1:len(s)-1] {
case "odin":
return .Odin;
case "contextless":
return .Contextless;
case "cdecl", "c":
return .C_Decl;
case "stdcall", "std":
return .Std_Call;
case "fast", "fastcall":
return .Fast_Call;
case "none":
return .None;
if len(s) == 2 {
return nil;
}
return .Invalid;
return s;
}
parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
@@ -1926,21 +1969,17 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
}
parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type {
cc := ast.Proc_Calling_Convention.Invalid;
cc: ast.Proc_Calling_Convention;
if p.curr_tok.kind == .String {
str := expect_token(p, .String);
cc = string_to_calling_convention(str.text);
if cc == ast.Proc_Calling_Convention.Invalid {
if cc == nil {
error(p, str.pos, "unknown calling convention '%s'", str.text);
}
}
if cc == ast.Proc_Calling_Convention.Invalid {
if p.in_foreign_block {
cc = ast.Proc_Calling_Convention.Foreign_Block_Default;
} else {
cc = ast.Proc_Calling_Convention.Odin;
}
if cc == nil && p.in_foreign_block {
cc = .Foreign_Block_Default;
}
expect_token(p, .Open_Paren);
@@ -1976,23 +2015,6 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type {
return pt;
}
check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok: tokenizer.Token) {
if poly_params == nil {
return;
}
for field in poly_params.list {
for name in field.names {
if name == nil {
continue;
}
if _, ok := name.derived.(ast.Poly_Type); ok {
error(p, name.pos, "polymorphic names are not needed for %s parameters", tok.text);
return;
}
}
}
}
parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ast.Expr {
expr := parse_unary_expr(p, lhs);
@@ -2224,6 +2246,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
p.expr_level = -1;
where_clauses = parse_rhs_expr_list(p);
p.expr_level = prev_level;
tags = parse_proc_tags(p);
}
if p.allow_type && p.expr_level < 0 {
if where_token.kind != .Invalid {
@@ -2233,6 +2256,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
body: ^ast.Stmt;
skip_possible_newline_for_literal(p);
if allow_token(p, .Undef) {
body = nil;
if where_token.kind != .Invalid {
@@ -2358,7 +2383,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
poly_params = nil;
}
expect_token_after(p, .Close_Paren, "parameter list");
check_poly_params_for_type(p, poly_params, tok);
}
prev_level := p.expr_level;
@@ -2405,6 +2429,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
p.expr_level = where_prev_level;
}
skip_possible_newline_for_literal(p);
expect_token(p, .Open_Brace);
fields, name_count = parse_field_list(p, .Close_Brace, ast.Field_Flags_Struct);
close := expect_token(p, .Close_Brace);
@@ -2434,7 +2459,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
poly_params = nil;
}
expect_token_after(p, .Close_Paren, "parameter list");
check_poly_params_for_type(p, poly_params, tok);
}
prev_level := p.expr_level;
@@ -2473,6 +2497,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
variants: [dynamic]^ast.Expr;
skip_possible_newline_for_literal(p);
expect_token_after(p, .Open_Brace, "union");
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
@@ -2503,6 +2528,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
if p.curr_tok.kind != .Open_Brace {
base_type = parse_type(p);
}
skip_possible_newline_for_literal(p);
open := expect_token(p, .Open_Brace);
fields := parse_elem_list(p);
close := expect_token(p, .Close_Brace);
@@ -2601,6 +2628,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
}
skip_possible_newline_for_literal(p);
open := expect_token(p, .Open_Brace);
asm_string := parse_expr(p, false);
expect_token(p, .Comma);
@@ -2811,7 +2839,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
open := expect_token(p, .Open_Bracket);
#partial switch p.curr_tok.kind {
case .Colon, .Ellipsis, .Range_Half:
case .Colon, .Ellipsis, .Range_Half, .Range_Full:
// NOTE(bill): Do not err yet
break;
case:
@@ -2819,7 +2847,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
}
#partial switch p.curr_tok.kind {
case .Ellipsis, .Range_Half:
case .Ellipsis, .Range_Half, .Range_Full:
error(p, p.curr_tok.pos, "expected a colon, not a range");
fallthrough;
case .Colon:
@@ -3150,6 +3178,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
case ast.For_Stmt: n.label = label;
case ast.Switch_Stmt: n.label = label;
case ast.Type_Switch_Stmt: n.label = label;
case ast.Range_Stmt: n.label = label;
}
}
+924
View File
@@ -0,0 +1,924 @@
package odin_printer
import "core:odin/ast"
import "core:odin/tokenizer"
import "core:strings"
import "core:runtime"
import "core:fmt"
import "core:unicode/utf8"
import "core:mem"
Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Enum, If, For, Proc_Lit};
Line_Type :: bit_set[Type_Enum];
/*
Represents an unwrapped line
*/
Line :: struct {
format_tokens: [dynamic]Format_Token,
finalized: bool,
used: bool,
depth: int,
types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking
}
/*
Represents a singular token in a unwrapped line
*/
Format_Token :: struct {
kind: tokenizer.Token_Kind,
text: string,
type: Type_Enum,
spaces_before: int,
parameter_count: int,
}
Printer :: struct {
string_builder: strings.Builder,
config: Config,
depth: int, //the identation depth
comments: [dynamic]^ast.Comment_Group,
latest_comment_index: int,
allocator: mem.Allocator,
file: ^ast.File,
source_position: tokenizer.Pos,
last_source_position: tokenizer.Pos,
lines: [dynamic]Line, //need to look into a better data structure, one that can handle inserting lines rather than appending
skip_semicolon: bool,
current_line: ^Line,
current_line_index: int,
last_line_index: int,
last_token: ^Format_Token,
merge_next_token: bool,
space_next_token: bool,
debug: bool,
}
Config :: struct {
spaces: int, //Spaces per indentation
newline_limit: int, //The limit of newlines between statements and declarations.
tabs: bool, //Enable or disable tabs
convert_do: bool, //Convert all do statements to brace blocks
semicolons: bool, //Enable semicolons
split_multiple_stmts: bool,
align_switch: bool,
brace_style: Brace_Style,
align_assignments: bool,
align_structs: bool,
align_style: Alignment_Style,
align_enums: bool,
align_length_break: int,
indent_cases: bool,
newline_style: Newline_Style,
}
Brace_Style :: enum {
_1TBS,
Allman,
Stroustrup,
K_And_R,
}
Block_Type :: enum {
None,
If_Stmt,
Proc,
Generic,
Comp_Lit,
Switch_Stmt,
}
Alignment_Style :: enum {
Align_On_Type_And_Equals,
Align_On_Colon_And_Equals,
}
Newline_Style :: enum {
CRLF,
LF,
}
default_style := Config {
spaces = 4,
newline_limit = 2,
convert_do = false,
semicolons = true,
tabs = true,
brace_style = ._1TBS,
split_multiple_stmts = true,
align_assignments = true,
align_style = .Align_On_Type_And_Equals,
indent_cases = false,
align_switch = true,
align_structs = true,
align_enums = true,
newline_style = .CRLF,
align_length_break = 9,
};
make_printer :: proc(config: Config, allocator := context.allocator) -> Printer {
return {
config = config,
allocator = allocator,
debug = false,
};
}
print :: proc(p: ^Printer, file: ^ast.File) -> string {
p.comments = file.comments;
if len(file.decls) > 0 {
p.lines = make([dynamic]Line, 0, (file.decls[len(file.decls) - 1].end.line - file.decls[0].pos.line) * 2, context.temp_allocator);
}
set_source_position(p, file.pkg_token.pos);
p.last_source_position.line = 1;
set_line(p, 0);
push_generic_token(p, .Package, 0);
push_ident_token(p, file.pkg_name, 1);
for decl in file.decls {
visit_decl(p, cast(^ast.Decl)decl);
}
if len(p.comments) > 0 {
infinite := p.comments[len(p.comments) - 1].end;
infinite.offset = 9999999;
push_comments(p, infinite);
}
fix_lines(p);
builder := strings.make_builder(0, mem.megabytes(5), p.allocator);
last_line := 0;
newline: string;
if p.config.newline_style == .LF {
newline = "\n";
} else {
newline = "\r\n";
}
for line, line_index in p.lines {
diff_line := line_index - last_line;
for i := 0; i < diff_line; i += 1 {
strings.write_string(&builder, newline);
}
if p.config.tabs {
for i := 0; i < line.depth; i += 1 {
strings.write_byte(&builder, '\t');
}
} else {
for i := 0; i < line.depth * p.config.spaces; i += 1 {
strings.write_byte(&builder, ' ');
}
}
if p.debug {
strings.write_string(&builder, fmt.tprintf("line %v: ", line_index));
}
for format_token in line.format_tokens {
for i := 0; i < format_token.spaces_before; i += 1 {
strings.write_byte(&builder, ' ');
}
strings.write_string(&builder, format_token.text);
}
last_line = line_index;
}
strings.write_string(&builder, newline);
return strings.to_string(builder);
}
fix_lines :: proc(p: ^Printer) {
align_var_decls(p);
format_generic(p);
align_comments(p); //align them last since they rely on the other alignments
}
format_value_decl :: proc(p: ^Printer, index: int) {
eq_found := false;
eq_token: Format_Token;
eq_line: int;
largest := 0;
found_eq: for line, line_index in p.lines[index:] {
for format_token in line.format_tokens {
largest += len(format_token.text) + format_token.spaces_before;
if format_token.kind == .Eq {
eq_token = format_token;
eq_line = line_index + index;
eq_found = true;
break found_eq;
}
}
}
if !eq_found {
return;
}
align_next := false;
//check to see if there is a binary operator in the last token(this is guaranteed by the ast visit), otherwise it's not multilined
for line, line_index in p.lines[eq_line:] {
if len(line.format_tokens) == 0 {
break;
}
if align_next {
line.format_tokens[0].spaces_before = largest + 1;
align_next = false;
}
kind := find_last_token(line.format_tokens).kind;
if tokenizer.Token_Kind.B_Operator_Begin < kind && kind <= tokenizer.Token_Kind.Cmp_Or {
align_next = true;
}
if !align_next {
break;
}
}
}
find_last_token :: proc(format_tokens: [dynamic]Format_Token) -> Format_Token {
for i := len(format_tokens) - 1; i >= 0; i -= 1 {
if format_tokens[i].kind != .Comment {
return format_tokens[i];
}
}
panic("not possible");
}
format_assignment :: proc(p: ^Printer, index: int) {
}
format_call :: proc(p: ^Printer, line_index: int, format_index: int) {
paren_found := false;
paren_token: Format_Token;
paren_line: int;
paren_token_index: int;
largest := 0;
found_paren: for line, i in p.lines[line_index:] {
for format_token, j in line.format_tokens {
largest += len(format_token.text) + format_token.spaces_before;
if i == 0 && j < format_index {
continue;
}
if format_token.kind == .Open_Paren && format_token.type == .Call {
paren_token = format_token;
paren_line = line_index + i;
paren_found = true;
paren_token_index = j;
break found_paren;
}
}
}
if !paren_found {
panic("Should not be possible");
}
paren_count := 1;
done := false;
for line, line_index in p.lines[paren_line:] {
if len(line.format_tokens) == 0 {
continue;
}
for format_token, i in line.format_tokens {
if format_token.kind == .Comment {
continue;
}
if line_index == 0 && i <= paren_token_index {
continue;
}
if format_token.kind == .Open_Paren {
paren_count += 1;
} else if format_token.kind == .Close_Paren {
paren_count -= 1;
}
if paren_count == 0 {
done = true;
}
}
if line_index != 0 {
line.format_tokens[0].spaces_before = largest;
}
if done {
return;
}
}
}
format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, keyword: tokenizer.Token_Kind) {
keyword_found := false;
keyword_token: Format_Token;
keyword_line: int;
largest := 0;
brace_count := 0;
done := false;
found_keyword: for line, i in p.lines[line_index:] {
for format_token in line.format_tokens {
largest += len(format_token.text) + format_token.spaces_before;
if format_token.kind == keyword {
keyword_token = format_token;
keyword_line = line_index + i;
keyword_found = true;
break found_keyword;
}
}
}
if !keyword_found {
panic("Should not be possible");
}
for line, line_index in p.lines[keyword_line:] {
if len(line.format_tokens) == 0 {
continue;
}
for format_token, i in line.format_tokens {
if format_token.kind == .Comment {
break;
} else if format_token.kind == .Undef {
return;
}
if line_index == 0 && i <= format_index {
continue;
}
if format_token.kind == .Open_Brace {
brace_count += 1;
} else if format_token.kind == .Close_Brace {
brace_count -= 1;
}
if brace_count == 1 {
done = true;
}
}
if line_index != 0 {
line.format_tokens[0].spaces_before = largest + 1;
}
if done {
return;
}
}
}
format_generic :: proc(p: ^Printer) {
next_struct_line := 0;
for line, line_index in p.lines {
if len(line.format_tokens) <= 0 {
continue;
}
for format_token, token_index in line.format_tokens {
#partial switch format_token.kind {
case .For, .If, .When, .Switch:
format_keyword_to_brace(p, line_index, token_index, format_token.kind);
case .Proc:
if format_token.type == .Proc_Lit {
format_keyword_to_brace(p, line_index, token_index, format_token.kind);
}
case:
if format_token.type == .Call {
format_call(p, line_index, token_index);
}
}
}
if .Switch_Stmt in line.types && p.config.align_switch {
align_switch_stmt(p, line_index);
}
if .Enum in line.types && p.config.align_enums {
align_enum(p, line_index);
}
if .Struct in line.types && p.config.align_structs && next_struct_line <= 0 {
next_struct_line = align_struct(p, line_index);
}
if .Value_Decl in line.types {
format_value_decl(p, line_index);
}
if .Assign in line.types {
format_assignment(p, line_index);
}
next_struct_line -= 1;
}
}
align_var_decls :: proc(p: ^Printer) {
current_line: int;
current_typed: bool;
current_not_mutable: bool;
largest_lhs := 0;
largest_rhs := 0;
TokenAndLength :: struct {
format_token: ^Format_Token,
length: int,
};
colon_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator);
type_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator);
equal_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator);
for line, line_index in p.lines {
//It is only possible to align value decls that are one one line, otherwise just ignore them
if .Value_Decl not_in line.types {
continue;
}
typed := true;
not_mutable := false;
continue_flag := false;
for i := 0; i < len(line.format_tokens); i += 1 {
if line.format_tokens[i].kind == .Colon && line.format_tokens[min(i + 1, len(line.format_tokens) - 1)].kind == .Eq {
typed = false;
}
if line.format_tokens[i].kind == .Colon && line.format_tokens[min(i + 1, len(line.format_tokens) - 1)].kind == .Colon {
not_mutable = true;
}
if line.format_tokens[i].kind == .Union ||
line.format_tokens[i].kind == .Enum ||
line.format_tokens[i].kind == .Struct ||
line.format_tokens[i].kind == .For ||
line.format_tokens[i].kind == .If ||
line.format_tokens[i].kind == .Comment {
continue_flag = true;
}
//enforced undef is always on the last line, if it exists
if line.format_tokens[i].kind == .Proc && line.format_tokens[len(line.format_tokens)-1].kind != .Undef {
continue_flag = true;
}
}
if continue_flag {
continue;
}
if line_index != current_line + 1 || typed != current_typed || not_mutable != current_not_mutable {
if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable {
for colon_token in colon_tokens {
colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1;
}
} else if p.config.align_style == .Align_On_Type_And_Equals {
for type_token in type_tokens {
type_token.format_token.spaces_before = largest_lhs - type_token.length + 1;
}
}
if current_typed {
for equal_token in equal_tokens {
equal_token.format_token.spaces_before = largest_rhs - equal_token.length + 1;
}
} else {
for equal_token in equal_tokens {
equal_token.format_token.spaces_before = 0;
}
}
clear(&colon_tokens);
clear(&type_tokens);
clear(&equal_tokens);
largest_rhs = 0;
largest_lhs = 0;
current_typed = typed;
current_not_mutable = not_mutable;
}
current_line = line_index;
current_token_index := 0;
lhs_length := 0;
rhs_length := 0;
//calcuate the length of lhs of a value decl i.e. `a, b:`
for; current_token_index < len(line.format_tokens); current_token_index += 1 {
lhs_length += len(line.format_tokens[current_token_index].text) + line.format_tokens[current_token_index].spaces_before;
if line.format_tokens[current_token_index].kind == .Colon {
append(&colon_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index], length = lhs_length});
if len(line.format_tokens) > current_token_index && line.format_tokens[current_token_index + 1].kind != .Eq {
append(&type_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index + 1], length = lhs_length});
}
current_token_index += 1;
largest_lhs = max(largest_lhs, lhs_length);
break;
}
}
//calcuate the length of the rhs i.e. `[dynamic]int = 123123`
for; current_token_index < len(line.format_tokens); current_token_index += 1 {
rhs_length += len(line.format_tokens[current_token_index].text) + line.format_tokens[current_token_index].spaces_before;
if line.format_tokens[current_token_index].kind == .Eq {
append(&equal_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index], length = rhs_length});
largest_rhs = max(largest_rhs, rhs_length);
break;
}
}
}
//repeating myself, move to sub procedure
if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable {
for colon_token in colon_tokens {
colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1;
}
} else if p.config.align_style == .Align_On_Type_And_Equals {
for type_token in type_tokens {
type_token.format_token.spaces_before = largest_lhs - type_token.length + 1;
}
}
if current_typed {
for equal_token in equal_tokens {
equal_token.format_token.spaces_before = largest_rhs - equal_token.length + 1;
}
} else {
for equal_token in equal_tokens {
equal_token.format_token.spaces_before = 0;
}
}
}
align_switch_stmt :: proc(p: ^Printer, index: int) {
switch_found := false;
brace_token: Format_Token;
brace_line: int;
found_switch_brace: for line, line_index in p.lines[index:] {
for format_token in line.format_tokens {
if format_token.kind == .Open_Brace && switch_found {
brace_token = format_token;
brace_line = line_index + index;
break found_switch_brace;
} else if format_token.kind == .Open_Brace {
break;
} else if format_token.kind == .Switch {
switch_found = true;
}
}
}
if !switch_found {
return;
}
largest := 0;
case_count := 0;
TokenAndLength :: struct {
format_token: ^Format_Token,
length: int,
};
format_tokens := make([dynamic]TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator);
//find all the switch cases that are one lined
for line, line_index in p.lines[brace_line + 1:] {
case_found := false;
colon_found := false;
length := 0;
for format_token, i in line.format_tokens {
if format_token.kind == .Comment {
break;
}
//this will only happen if the case is one lined
if case_found && colon_found {
append(&format_tokens, TokenAndLength {format_token = &line.format_tokens[i], length = length});
largest = max(length, largest);
break;
}
if format_token.kind == .Case {
case_found = true;
case_count += 1;
} else if format_token.kind == .Colon {
colon_found = true;
}
length += len(format_token.text) + format_token.spaces_before;
}
if case_count >= brace_token.parameter_count {
break;
}
}
for token in format_tokens {
token.format_token.spaces_before = largest - token.length + 1;
}
}
align_enum :: proc(p: ^Printer, index: int) {
enum_found := false;
brace_token: Format_Token;
brace_line: int;
found_enum_brace: for line, line_index in p.lines[index:] {
for format_token in line.format_tokens {
if format_token.kind == .Open_Brace && enum_found {
brace_token = format_token;
brace_line = line_index + index;
break found_enum_brace;
} else if format_token.kind == .Open_Brace {
break;
} else if format_token.kind == .Enum {
enum_found = true;
}
}
}
if !enum_found {
return;
}
largest := 0;
comma_count := 0;
TokenAndLength :: struct {
format_token: ^Format_Token,
length: int,
};
format_tokens := make([dynamic]TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator);
for line, line_index in p.lines[brace_line + 1:] {
length := 0;
for format_token, i in line.format_tokens {
if format_token.kind == .Comment {
break;
}
if format_token.kind == .Eq {
append(&format_tokens, TokenAndLength {format_token = &line.format_tokens[i], length = length});
largest = max(length, largest);
break;
} else if format_token.kind == .Comma {
comma_count += 1;
}
length += len(format_token.text) + format_token.spaces_before;
}
if comma_count >= brace_token.parameter_count {
break;
}
}
for token in format_tokens {
token.format_token.spaces_before = largest - token.length + 1;
}
}
align_struct :: proc(p: ^Printer, index: int) -> int {
struct_found := false;
brace_token: Format_Token;
brace_line: int;
found_struct_brace: for line, line_index in p.lines[index:] {
for format_token in line.format_tokens {
if format_token.kind == .Open_Brace && struct_found {
brace_token = format_token;
brace_line = line_index + index;
break found_struct_brace;
} else if format_token.kind == .Open_Brace {
break;
} else if format_token.kind == .Struct {
struct_found = true;
}
}
}
if !struct_found {
return 0;
}
largest := 0;
colon_count := 0;
nested := false;
seen_brace := false;
TokenAndLength :: struct {
format_token: ^Format_Token,
length: int,
};
format_tokens := make([]TokenAndLength, brace_token.parameter_count, context.temp_allocator);
if brace_token.parameter_count == 0 {
return 0;
}
end_line_index := 0;
for line, line_index in p.lines[brace_line + 1:] {
length := 0;
for format_token, i in line.format_tokens {
//give up on nested structs
if format_token.kind == .Comment {
break;
} else if format_token.kind == .Open_Paren {
break;
} else if format_token.kind == .Open_Brace {
seen_brace = true;
} else if format_token.kind == .Close_Brace {
seen_brace = false;
} else if seen_brace {
continue;
}
if format_token.kind == .Colon {
format_tokens[colon_count] = {format_token = &line.format_tokens[i + 1], length = length};
if format_tokens[colon_count].format_token.kind == .Struct {
nested = true;
}
colon_count += 1;
largest = max(length, largest);
}
length += len(format_token.text) + format_token.spaces_before;
}
if nested {
end_line_index = line_index + brace_line + 1;
}
if colon_count >= brace_token.parameter_count {
break;
}
}
//give up aligning nested, it never looks good
if nested {
for line, line_index in p.lines[end_line_index:] {
for format_token in line.format_tokens {
if format_token.kind == .Close_Brace {
return end_line_index + line_index - index;
}
}
}
}
for token in format_tokens {
token.format_token.spaces_before = largest - token.length + 1;
}
return 0;
}
align_comments :: proc(p: ^Printer) {
Comment_Align_Info :: struct {
length: int,
begin: int,
end: int,
depth: int,
};
comment_infos := make([dynamic]Comment_Align_Info, 0, context.temp_allocator);
current_info: Comment_Align_Info;
for line, line_index in p.lines {
if len(line.format_tokens) <= 0 {
continue;
}
if .Line_Comment in line.types {
if current_info.end + 1 != line_index || current_info.depth != line.depth ||
(current_info.begin == current_info.end && current_info.length == 0) {
if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 {
append(&comment_infos, current_info);
}
current_info.begin = line_index;
current_info.end = line_index;
current_info.depth = line.depth;
current_info.length = 0;
}
length := 0;
for format_token, i in line.format_tokens {
if format_token.kind == .Comment {
current_info.length = max(current_info.length, length);
current_info.end = line_index;
}
length += format_token.spaces_before + len(format_token.text);
}
}
}
if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 {
append(&comment_infos, current_info);
}
for info in comment_infos {
if info.begin == info.end || info.length == 0 {
continue;
}
for i := info.begin; i <= info.end; i += 1 {
l := p.lines[i];
length := 0;
for format_token, i in l.format_tokens {
if format_token.kind == .Comment {
if len(l.format_tokens) == 1 {
l.format_tokens[i].spaces_before = info.length + 1;
} else {
l.format_tokens[i].spaces_before = info.length - length + 1;
}
}
length += format_token.spaces_before + len(format_token.text);
}
}
}
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -107,6 +107,7 @@ Token_Kind :: enum u32 {
Comma, // ,
Ellipsis, // ..
Range_Half, // ..<
Range_Full, // ..=
Back_Slash, // \
B_Operator_End,
@@ -233,6 +234,7 @@ tokens := [Token_Kind.COUNT]string {
",",
"..",
"..<",
"..=",
"\\",
"",
+7 -4
View File
@@ -14,7 +14,7 @@ Flags :: distinct bit_set[Flag; u32];
Tokenizer :: struct {
// Immutable data
path: string,
src: []byte,
src: string,
err: Error_Handler,
flags: Flags,
@@ -31,7 +31,7 @@ Tokenizer :: struct {
error_count: int,
}
init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = default_error_handler) {
init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = default_error_handler) {
t.src = src;
t.err = err;
t.ch = ' ';
@@ -87,7 +87,7 @@ advance_rune :: proc(using t: ^Tokenizer) {
case r == 0:
error(t, t.offset, "illegal character NUL");
case r >= utf8.RUNE_SELF:
r, w = utf8.decode_rune(src[read_offset:]);
r, w = utf8.decode_rune_in_string(src[read_offset:]);
if r == utf8.RUNE_ERROR && w == 1 {
error(t, t.offset, "illegal UTF-8 encoding");
} else if r == utf8.RUNE_BOM && offset > 0 {
@@ -608,7 +608,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
}
case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
case '~': kind = .Xor;
case '~': kind = switch2(t, .Xor, .Xor_Eq);
case '<': kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
@@ -623,6 +623,9 @@ scan :: proc(t: ^Tokenizer) -> Token {
if t.ch == '<' {
advance_rune(t);
kind = .Range_Half;
} else if t.ch == '=' {
advance_rune(t);
kind = .Range_Full;
}
}
}
+3 -3
View File
@@ -273,7 +273,7 @@ is_file :: proc(path: string) -> bool {
attribs := win32.GetFileAttributesW(wpath);
if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES {
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == win32.FILE_ATTRIBUTE_DIRECTORY;
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0;
}
return false;
}
@@ -283,7 +283,7 @@ is_dir :: proc(path: string) -> bool {
attribs := win32.GetFileAttributesW(wpath);
if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES {
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != win32.FILE_ATTRIBUTE_DIRECTORY;
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0;
}
return false;
}
@@ -347,7 +347,7 @@ is_abs :: proc(path: string) -> bool {
when ODIN_OS == "windows" {
if len(path) > 2 {
switch path[0] {
case 'A'..'Z', 'a'..'z':
case 'A'..='Z', 'a'..='z':
return path[1] == ':' && is_path_separator(path[2]);
}
}
+18 -47
View File
@@ -1,11 +1,8 @@
package os2
Platform_Error_Min_Bits :: 32;
import "core:io"
Error :: enum u64 {
None = 0,
// General Errors
General_Error :: enum u32 {
Invalid_Argument,
Permission_Denied,
@@ -13,43 +10,20 @@ Error :: enum u64 {
Not_Exist,
Closed,
// Timeout Errors
Timeout,
// I/O Errors
// EOF is the error returned by `read` when no more input is available
EOF,
// Unexpected_EOF means that EOF was encountered in the middle of reading a fixed-sized block of data
Unexpected_EOF,
// Short_Write means that a write accepted fewer bytes than requested but failed to return an explicit error
Short_Write,
// Invalid_Write means that a write returned an impossible count
Invalid_Write,
// Short_Buffer means that a read required a longer buffer than was provided
Short_Buffer,
// No_Progress is returned by some implementations of `io.Reader` when many calls
// to `read` have failed to return any data or error.
// This is usually a signed of a broken `io.Reader` implementation
No_Progress,
Invalid_Whence,
Invalid_Offset,
Invalid_Unread,
Negative_Read,
Negative_Write,
Negative_Count,
Buffer_Full,
// Platform Specific Errors
Platform_Minimum = 1<<Platform_Error_Min_Bits,
}
Platform_Error :: struct {
err: i32,
}
Error :: union {
General_Error,
io.Error,
Platform_Error,
}
#assert(size_of(Error) == size_of(u64));
Path_Error :: struct {
op: string,
path: string,
@@ -83,20 +57,17 @@ link_error_delete :: proc(lerr: Maybe(Link_Error)) {
is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
if ferr >= .Platform_Minimum {
err = i32(u64(ferr)>>Platform_Error_Min_Bits);
ok = true;
v: Platform_Error;
if v, ok = ferr.(Platform_Error); ok {
err = v.err;
}
return;
}
error_from_platform_error :: proc(errno: i32) -> Error {
return Error(u64(errno) << Platform_Error_Min_Bits);
}
error_string :: proc(ferr: Error) -> string {
#partial switch ferr {
case .None: return "";
switch ferr {
case nil: return "";
case .Invalid_Argument: return "invalid argument";
case .Permission_Denied: return "permission denied";
case .Exist: return "file already exists";
+7 -16
View File
@@ -10,23 +10,14 @@ file_to_stream :: proc(fd: Handle) -> (s: io.Stream) {
@(private)
error_to_io_error :: proc(ferr: Error) -> io.Error {
#partial switch ferr {
case .None: return .None;
case .EOF: return .EOF;
case .Unexpected_EOF: return .Unexpected_EOF;
case .Short_Write: return .Short_Write;
case .Invalid_Write: return .Invalid_Write;
case .Short_Buffer: return .Short_Buffer;
case .No_Progress: return .No_Progress;
case .Invalid_Whence: return .Invalid_Whence;
case .Invalid_Offset: return .Invalid_Offset;
case .Invalid_Unread: return .Invalid_Unread;
case .Negative_Read: return .Negative_Read;
case .Negative_Write: return .Negative_Write;
case .Negative_Count: return .Negative_Count;
case .Buffer_Full: return .Buffer_Full;
if ferr == nil {
return .None;
}
return .Unknown;
err, ok := ferr.(io.Error);
if !ok {
err = .Unknown;
}
return err;
}
+1
View File
@@ -1,6 +1,7 @@
package os2
import "core:mem"
import "core:io"
import "core:strconv"
import "core:unicode/utf8"
+10 -10
View File
@@ -5,19 +5,19 @@ import "core:io"
import "core:time"
_create :: proc(name: string) -> (Handle, Error) {
return 0, .None;
return 0, nil;
}
_open :: proc(name: string) -> (Handle, Error) {
return 0, .None;
return 0, nil;
}
_open_file :: proc(name: string, flag: int, perm: File_Mode) -> (Handle, Error) {
return 0, .None;
return 0, nil;
}
_close :: proc(fd: Handle) -> Error {
return .None;
return nil;
}
_name :: proc(fd: Handle, allocator := context.allocator) -> string {
@@ -58,11 +58,11 @@ _file_size :: proc(fd: Handle) -> (n: i64, err: Error) {
_sync :: proc(fd: Handle) -> Error {
return .None;
return nil;
}
_flush :: proc(fd: Handle) -> Error {
return .None;
return nil;
}
_truncate :: proc(fd: Handle, size: i64) -> Maybe(Path_Error) {
@@ -92,20 +92,20 @@ _read_link :: proc(name: string) -> (string, Maybe(Path_Error)) {
_chdir :: proc(fd: Handle) -> Error {
return .None;
return nil;
}
_chmod :: proc(fd: Handle, mode: File_Mode) -> Error {
return .None;
return nil;
}
_chown :: proc(fd: Handle, uid, gid: int) -> Error {
return .None;
return nil;
}
_lchown :: proc(name: string, uid, gid: int) -> Error {
return .None;
return nil;
}
+2 -2
View File
@@ -12,8 +12,8 @@ heap_allocator :: proc() -> runtime.Allocator {
heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
return _heap_allocator_proc(allocator_data, mode, size, alignment, old_memory, old_size, flags, loc);
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, runtime.Allocator_Error) {
return _heap_allocator_proc(allocator_data, mode, size, alignment, old_memory, old_size, loc);
}
+11 -11
View File
@@ -27,9 +27,9 @@ heap_free :: proc(ptr: rawptr) {
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
}
_heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
_heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
//
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
// Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
@@ -37,7 +37,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mod
// the pointer we return to the user.
//
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil) -> rawptr {
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
a := max(alignment, align_of(rawptr));
space := size + a - 1;
@@ -54,13 +54,13 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mod
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a);
diff := int(aligned_ptr - ptr);
if (size + diff) > space {
return nil;
return nil, .Out_Of_Memory;
}
aligned_mem = rawptr(aligned_ptr);
mem.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem;
return aligned_mem;
return mem.byte_slice(aligned_mem, size), nil;
}
aligned_free :: proc(p: rawptr) {
@@ -69,9 +69,9 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mod
}
}
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> rawptr {
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) {
if p == nil {
return nil;
return nil, nil;
}
return aligned_alloc(new_size, new_alignment, p);
}
@@ -93,15 +93,15 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mod
return aligned_resize(old_memory, old_size, size, alignment);
case .Query_Features:
set := (^runtime.Allocator_Mode_Set)(old_memory);
set := (^mem.Allocator_Mode_Set)(old_memory);
if set != nil {
set^ = {.Alloc, .Free, .Resize, .Query_Features};
}
return set;
return nil, nil;
case .Query_Info:
return nil;
return nil, nil;
}
return nil;
return nil, nil;
}
+1 -1
View File
@@ -6,7 +6,7 @@ import win32 "core:sys/windows"
_pipe :: proc() -> (r, w: Handle, err: Error) {
p: [2]win32.HANDLE;
if !win32.CreatePipe(&p[0], &p[1], nil, 0) {
return 0, 0, error_from_platform_error(i32(win32.GetLastError()));
return 0, 0, Platform_Error{i32(win32.GetLastError())};
}
return Handle(p[0]), Handle(p[1]), nil;
}
+4 -4
View File
@@ -40,7 +40,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
_stat_errno :: proc(errno: win32.DWORD) -> Path_Error {
return Path_Error{err = error_from_platform_error(i32(errno))};
return Path_Error{err = Platform_Error{i32(errno)}};
}
@@ -89,7 +89,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
fd: win32.WIN32_FIND_DATAW;
sh := win32.FindFirstFileW(wname, &fd);
if sh == win32.INVALID_HANDLE_VALUE {
e = Path_Error{err = error_from_platform_error(i32(win32.GetLastError()))};
e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}};
return;
}
win32.FindClose(sh);
@@ -99,7 +99,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil);
if h == win32.INVALID_HANDLE_VALUE {
e = Path_Error{err = error_from_platform_error(i32(win32.GetLastError()))};
e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}};
return;
}
defer win32.CloseHandle(h);
@@ -322,7 +322,7 @@ _is_abs :: proc(path: string) -> bool {
}
if len(path) > 2 {
switch path[0] {
case 'A'..'Z', 'a'..'z':
case 'A'..='Z', 'a'..='z':
return path[1] == ':' && is_path_separator(path[2]);
}
}
+2 -2
View File
@@ -4,11 +4,11 @@ package os2
import win32 "core:sys/windows"
_create_temp :: proc(dir, pattern: string) -> (Handle, Error) {
return 0, .None;
return 0, nil;
}
_mkdir_temp :: proc(dir, pattern: string, allocator := context.allocator) -> (string, Error) {
return "", .None;
return "", nil;
}
_temp_dir :: proc(allocator := context.allocator) -> string {
+2 -2
View File
@@ -302,7 +302,7 @@ foreign libc {
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---;
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---;
@(link_name="exit") _unix_exit :: proc(status: int) ---;
@(link_name="exit") _unix_exit :: proc(status: int) -> ! ---;
}
foreign dl {
@@ -337,7 +337,7 @@ write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
return 0, 0;
}
bytes_written := _unix_write(fd, raw_data(data), len(data));
if(bytes_written == -1) {
if bytes_written == -1 {
return 0, 1;
}
return bytes_written, 0;
+1 -1
View File
@@ -10,7 +10,7 @@ import "core:c"
Handle :: distinct i32;
File_Time :: distinct u64;
Errno :: distinct i32;
Syscall :: distinct int;
Syscall :: distinct i32;
INVALID_HANDLE :: ~Handle(0);
+3 -2
View File
@@ -35,8 +35,9 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn
close :: proc(fd: Handle) -> Errno {
return 0;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
return 0, 0;
}
current_thread_id :: proc "contextless" () -> int {
return 0;
}
+3 -3
View File
@@ -11,7 +11,7 @@ import "core:strconv"
Handle :: distinct i32;
File_Time :: distinct u64;
Errno :: distinct i32;
Syscall :: distinct int;
Syscall :: distinct i32;
INVALID_HANDLE :: ~Handle(0);
@@ -269,7 +269,7 @@ SYS_GETTID: Syscall : 186;
foreign libc {
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---;
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> i32 ---;
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---;
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---;
@@ -595,7 +595,7 @@ exit :: proc "contextless" (code: int) -> ! {
}
current_thread_id :: proc "contextless" () -> int {
return syscall(SYS_GETTID);
return cast(int)syscall(SYS_GETTID);
}
dlopen :: proc(filename: string, flags: int) -> rawptr {
+2 -2
View File
@@ -11,14 +11,14 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
}
p := win32.utf8_to_utf16(name, context.temp_allocator);
buf := make([dynamic]u16, 100, allocator);
defer delete(buf);
for {
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil);
if n == 0 {
delete(buf);
return "", Errno(win32.GetLastError());
}
if n <= u32(len(buf)) {
return win32.utf16_to_utf8(buf[:n]), ERROR_NONE;
return win32.utf16_to_utf8(buf[:n], allocator), ERROR_NONE;
}
resize(&buf, len(buf)*2);
}
+14 -8
View File
@@ -39,7 +39,7 @@ volume_name_len :: proc(path: string) -> int {
c := path[0];
if path[1] == ':' {
switch c {
case 'a'..'z', 'A'..'Z':
case 'a'..='z', 'A'..='Z':
return 2;
}
}
@@ -170,6 +170,7 @@ clean :: proc(path: string, allocator := context.allocator) -> string {
cleaned, new_allocation := from_slash(s);
if new_allocation {
delete(s);
lazy_buffer_destroy(out);
}
return cleaned;
}
@@ -206,23 +207,23 @@ Relative_Error :: enum {
rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (string, Relative_Error) {
context.allocator = allocator;
base_vol, target_vol := volume_name(base_path), volume_name(target_path);
base, target := clean(base_path), clean(target_path);
base_clean, target_clean := clean(base_path), clean(target_path);
delete_target := true;
defer {
if delete_target {
delete(target);
delete(target_clean);
}
delete(base);
delete(base_clean);
}
if strings.equal_fold(target, base) {
if strings.equal_fold(target_clean, base_clean) {
return strings.clone("."), .None;
}
base = base[len(base_vol):];
target = target[len(target_vol):];
base_vol, target_vol := volume_name(base_path), volume_name(target_path);
base := base_clean[len(base_vol):];
target := target_clean[len(target_vol):];
if base == "." {
base = "";
}
@@ -395,3 +396,8 @@ lazy_buffer_string :: proc(lb: ^Lazy_Buffer) -> string {
copy(z[len(x):], y);
return string(z);
}
@(private)
lazy_buffer_destroy :: proc(lb: ^Lazy_Buffer) {
delete(lb.b);
lb^ = {};
}
+1 -1
View File
@@ -5,7 +5,7 @@ import "core:mem"
_ :: runtime;
_ :: mem;
Map_Entry_Info :: struct(Key, Value: typeid) {
Map_Entry_Info :: struct($Key, $Value: typeid) {
hash: uintptr,
key: Key,
value: Value,
+63 -21
View File
@@ -33,6 +33,8 @@ Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector;
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer;
Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice;
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value;
Type_Kind :: enum {
Invalid,
@@ -111,7 +113,7 @@ backing_type_kind :: proc(T: typeid) -> Type_Kind {
}
type_info_base :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil { return nil; }
base := info;
@@ -125,7 +127,7 @@ type_info_base :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
}
type_info_core :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
type_info_core :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil { return nil; }
base := info;
@@ -344,7 +346,7 @@ Struct_Tag :: distinct string;
Struct_Field :: struct {
name: string,
type: typeid,
type: ^Type_Info,
tag: Struct_Tag,
offset: uintptr,
is_using: bool,
@@ -355,7 +357,7 @@ struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
if 0 <= i && i < len(s.names) {
field.name = s.names[i];
field.type = s.types[i].id;
field.type = s.types[i];
field.tag = Struct_Tag(s.tags[i]);
field.offset = s.offsets[i];
field.is_using = s.usings[i];
@@ -370,7 +372,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
for fname, i in s.names {
if fname == name {
field.name = s.names[i];
field.type = s.types[i].id;
field.type = s.types[i];
field.tag = Struct_Tag(s.tags[i]);
field.offset = s.offsets[i];
field.is_using = s.usings[i];
@@ -381,7 +383,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
return;
}
struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
if a == nil { return nil; }
ti := runtime.type_info_base(type_info_of(a.id));
@@ -395,13 +397,13 @@ struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> a
};
}
if recurse && s.usings[i] {
if allow_using && s.usings[i] {
f := any{
rawptr(uintptr(a.data) + s.offsets[i]),
s.types[i].id,
};
if res := struct_field_value_by_name(f, field, recurse); res != nil {
if res := struct_field_value_by_name(f, field, allow_using); res != nil {
return res;
}
}
@@ -420,7 +422,7 @@ struct_field_names :: proc(T: typeid) -> []string {
return nil;
}
struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
struct_field_types :: proc(T: typeid) -> []^Type_Info {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.types;
@@ -445,6 +447,20 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
return nil;
}
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return soa_zip(
name = s.names,
type = s.types,
tag = transmute([]Struct_Tag)s.tags,
offset = s.offsets,
is_using = s.usings,
);
}
return nil;
}
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
@@ -468,7 +484,7 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, o
switch t[i] {
case ':', '"':
break loop;
case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
case 0x00 ..< ' ', 0x7f ..= 0x9f: // break if control character is found
break loop;
}
i += 1;
@@ -516,7 +532,7 @@ enum_string :: proc(a: any) -> string {
if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
v, _ := as_i64(a);
for value, i in e.values {
if value == runtime.Type_Info_Enum_Value(v) {
if value == Type_Info_Enum_Value(v) {
return e.names[i];
}
}
@@ -528,26 +544,24 @@ enum_string :: proc(a: any) -> string {
}
// Given a enum type and a value name, get the enum value.
enum_from_name :: proc($EnumType: typeid, name: string) -> (value: EnumType, ok: bool) {
ti := type_info_base(type_info_of(EnumType));
enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
ti := type_info_base(type_info_of(Enum_Type));
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
for value_name, i in eti.names {
if value_name != name {
continue;
}
v := eti.values[i];
value = EnumType(v);
value = Enum_Type(v);
ok = true;
return;
}
} else {
panic("expected enum type to reflect.enum_from_name");
}
return;
}
enum_from_name_any :: proc(EnumType: typeid, name: string) -> (value: runtime.Type_Info_Enum_Value, ok: bool) {
ti := runtime.type_info_base(type_info_of(EnumType));
enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
ti := runtime.type_info_base(type_info_of(Enum_Type));
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
for value_name, i in eti.names {
if value_name != name {
@@ -557,14 +571,42 @@ enum_from_name_any :: proc(EnumType: typeid, name: string) -> (value: runtime.Ty
ok = true;
return;
}
} else {
panic("expected enum type to reflect.enum_from_name_any");
}
return;
}
union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
enum_field_names :: proc(Enum_Type: typeid) -> []string {
ti := runtime.type_info_base(type_info_of(Enum_Type));
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
return eti.names;
}
return nil;
}
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
ti := runtime.type_info_base(type_info_of(Enum_Type));
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
return eti.values;
}
return nil;
}
Enum_Field :: struct {
name: string,
value: Type_Info_Enum_Value,
}
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
ti := runtime.type_info_base(type_info_of(Enum_Type));
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
return soa_zip(name=eti.names, value=eti.values);
}
return nil;
}
union_variant_type_info :: proc(a: any) -> ^Type_Info {
id := union_variant_typeid(a);
return type_info_of(id);
}
+14 -20
View File
@@ -20,6 +20,8 @@
//
package runtime
import "intrinsics"
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum u8 {
Invalid = 0,
@@ -30,6 +32,7 @@ Calling_Convention :: enum u8 {
Fast_Call = 5,
None = 6,
Naked = 7,
}
Type_Info_Enum_Value :: distinct i64;
@@ -118,6 +121,9 @@ Type_Info_Union :: struct {
variants: []^Type_Info,
tag_offset: uintptr,
tag_type: ^Type_Info,
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
custom_align: bool,
no_nil: bool,
maybe: bool,
@@ -249,7 +255,7 @@ Source_Code_Location :: struct {
procedure: string,
}
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location);
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> !;
// Allocation Stuff
Allocator_Mode :: enum byte {
@@ -323,8 +329,6 @@ Context :: struct {
assertion_failure_proc: Assertion_Failure_Proc,
logger: Logger,
thread_id: int,
user_data: any,
user_ptr: rawptr,
user_index: int,
@@ -407,7 +411,7 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
}
type_info_base_without_enum :: type_info_core;
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check {
MASK :: 1<<(8*size_of(typeid) - 8) - 1;
data := transmute(uintptr)id;
n := int(data & MASK);
@@ -430,17 +434,9 @@ typeid_base_without_enum :: typeid_core;
@(default_calling_convention = "none")
foreign {
@(link_name="llvm.debugtrap")
debug_trap :: proc() ---;
@(link_name="llvm.trap")
trap :: proc() -> ! ---;
@(link_name="llvm.readcyclecounter")
read_cycle_counter :: proc() -> u64 ---;
}
debug_trap :: intrinsics.debug_trap;
trap :: intrinsics.trap;
read_cycle_counter :: intrinsics.read_cycle_counter;
@@ -481,15 +477,13 @@ __init_context :: proc "contextless" (c: ^Context) {
c.temp_allocator.procedure = default_temp_allocator_proc;
c.temp_allocator.data = &global_default_temp_allocator_data;
c.thread_id = current_thread_id(); // NOTE(bill): This is "contextless" so it is okay to call
c.assertion_failure_proc = default_assertion_failure_proc;
c.logger.procedure = default_logger_proc;
c.logger.data = nil;
}
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) {
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
print_caller_location(loc);
print_string(" ");
print_string(prefix);
@@ -498,6 +492,6 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
print_string(message);
}
print_byte('\n');
debug_trap();
// trap();
// debug_trap();
trap();
}
+25 -32
View File
@@ -1,7 +1,9 @@
package runtime
import "intrinsics"
@builtin
Maybe :: union(T: typeid) #maybe {T};
Maybe :: union($T: typeid) #maybe {T};
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator;
@@ -15,7 +17,7 @@ init_global_temporary_allocator :: proc(size: int, backup_allocator := context.a
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
n := max(0, min(len(dst), len(src)));
if n > 0 {
mem_copy(raw_data(dst), raw_data(src), n*size_of(E));
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E));
}
return n;
}
@@ -23,7 +25,7 @@ copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
n := max(0, min(len(dst), len(src)));
if n > 0 {
mem_copy(raw_data(dst), raw_data(src), n);
intrinsics.mem_copy(raw_data(dst), raw_data(src), n);
}
return n;
}
@@ -33,26 +35,26 @@ copy :: proc{copy_slice, copy_from_string};
@builtin
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array));
n := len(array)-1;
if index != n {
array[index] = array[n];
}
pop(array);
(^Raw_Dynamic_Array)(array).len -= 1;
}
@builtin
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array));
if index+1 < len(array) {
copy(array[index:], array[index+1:]);
}
pop(array);
(^Raw_Dynamic_Array)(array).len -= 1;
}
@builtin
remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) {
remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check {
slice_expr_error_lo_hi_loc(loc, lo, hi, len(array));
n := max(hi-lo, 0);
if n > 0 {
@@ -283,22 +285,18 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
return;
}
arg_len := 1;
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len);
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1);
_ = reserve(array, cap, loc);
}
arg_len = min(cap(array)-len(array), arg_len);
if arg_len > 0 {
if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array);
if size_of(E) != 0 {
when size_of(E) != 0 {
data := (^E)(a.data);
assert(data != nil);
val := arg;
mem_copy(ptr_offset(data, a.len), &val, size_of(E));
assert(condition=data != nil, loc=loc);
intrinsics.ptr_offset(data, a.len)^ = arg;
}
a.len += arg_len;
a.len += 1;
}
}
@@ -321,10 +319,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
arg_len = min(cap(array)-len(array), arg_len);
if arg_len > 0 {
a := (^Raw_Dynamic_Array)(array);
if size_of(E) != 0 {
when size_of(E) != 0 {
data := (^E)(a.data);
assert(data != nil);
mem_copy(ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
assert(condition=data != nil, loc=loc);
intrinsics.mem_copy(intrinsics.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
}
a.len += arg_len;
}
@@ -539,20 +537,15 @@ excl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
@builtin
card :: proc(s: $S/bit_set[$E; $U]) -> int {
when size_of(S) == 1 {
foreign { @(link_name="llvm.ctpop.i8") count_ones :: proc(i: u8) -> u8 --- }
return int(count_ones(transmute(u8)s));
return int(intrinsics.count_ones(transmute(u8)s));
} else when size_of(S) == 2 {
foreign { @(link_name="llvm.ctpop.i16") count_ones :: proc(i: u16) -> u16 --- }
return int(count_ones(transmute(u16)s));
return int(intrinsics.count_ones(transmute(u16)s));
} else when size_of(S) == 4 {
foreign { @(link_name="llvm.ctpop.i32") count_ones :: proc(i: u32) -> u32 --- }
return int(count_ones(transmute(u32)s));
return int(intrinsics.count_ones(transmute(u32)s));
} else when size_of(S) == 8 {
foreign { @(link_name="llvm.ctpop.i64") count_ones :: proc(i: u64) -> u64 --- }
return int(count_ones(transmute(u64)s));
return int(intrinsics.count_ones(transmute(u64)s));
} else when size_of(S) == 16 {
foreign { @(link_name="llvm.ctpop.i128") count_ones :: proc(i: u128) -> u128 --- }
return int(count_ones(transmute(u128)s));
return int(intrinsics.count_ones(transmute(u128)s));
} else {
#panic("Unhandled card bit_set size");
}
-205
View File
@@ -1,205 +0,0 @@
package runtime
when ODIN_DEFAULT_TO_NIL_ALLOCATOR || ODIN_OS == "freestanding" {
// mem.nil_allocator reimplementation
default_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
return nil, .None;
}
default_allocator :: proc() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
}
} else when ODIN_OS != "windows" {
// TODO(bill): reimplement these procedures in the os_specific stuff
import "core:os"
default_allocator_proc :: os.heap_allocator_proc;
default_allocator :: proc() -> Allocator {
return os.heap_allocator();
}
}
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte {
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)};
}
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22);
Default_Temp_Allocator :: struct {
data: []byte,
curr_offset: int,
prev_allocation: rawptr,
backup_allocator: Allocator,
leaked_allocations: [dynamic][]byte,
}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator);
s.curr_offset = 0;
s.prev_allocation = nil;
s.backup_allocator = backup_allocator;
s.leaked_allocations.allocator = backup_allocator;
}
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
if s == nil {
return;
}
for ptr in s.leaked_allocations {
free(raw_data(ptr), s.backup_allocator);
}
delete(s.leaked_allocations);
delete(s.data, s.backup_allocator);
s^ = {};
}
default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
s := (^Default_Temp_Allocator)(allocator_data);
if s.data == nil {
default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator());
}
size := size;
switch mode {
case .Alloc:
size = align_forward_int(size, alignment);
switch {
case s.curr_offset+size <= len(s.data):
start := uintptr(raw_data(s.data));
ptr := start + uintptr(s.curr_offset);
ptr = align_forward_uintptr(ptr, uintptr(alignment));
mem_zero(rawptr(ptr), size);
s.prev_allocation = rawptr(ptr);
offset := int(ptr - start);
s.curr_offset = offset + size;
return byte_slice(rawptr(ptr), size), .None;
case size <= len(s.data):
start := uintptr(raw_data(s.data));
ptr := align_forward_uintptr(start, uintptr(alignment));
mem_zero(rawptr(ptr), size);
s.prev_allocation = rawptr(ptr);
offset := int(ptr - start);
s.curr_offset = offset + size;
return byte_slice(rawptr(ptr), size), .None;
}
a := s.backup_allocator;
if a.procedure == nil {
a = context.allocator;
s.backup_allocator = a;
}
data, err := mem_alloc_bytes(size, alignment, a, loc);
if err != nil {
return data, err;
}
if s.leaked_allocations == nil {
s.leaked_allocations = make([dynamic][]byte, a);
}
append(&s.leaked_allocations, data);
// TODO(bill): Should leaks be notified about?
if logger := context.logger; logger.lowest_level <= .Warning {
if logger.procedure != nil {
logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc);
}
}
return data, .None;
case .Free:
if old_memory == nil {
return nil, .None;
}
start := uintptr(raw_data(s.data));
end := start + uintptr(len(s.data));
old_ptr := uintptr(old_memory);
if s.prev_allocation == old_memory {
s.curr_offset = int(uintptr(s.prev_allocation) - start);
s.prev_allocation = nil;
return nil, .None;
}
if start <= old_ptr && old_ptr < end {
// NOTE(bill): Cannot free this pointer but it is valid
return nil, .None;
}
if len(s.leaked_allocations) != 0 {
for data, i in s.leaked_allocations {
ptr := raw_data(data);
if ptr == old_memory {
free(ptr, s.backup_allocator);
ordered_remove(&s.leaked_allocations, i);
return nil, .None;
}
}
}
return nil, .Invalid_Pointer;
// panic("invalid pointer passed to default_temp_allocator");
case .Free_All:
s.curr_offset = 0;
s.prev_allocation = nil;
for data in s.leaked_allocations {
free(raw_data(data), s.backup_allocator);
}
clear(&s.leaked_allocations);
case .Resize:
begin := uintptr(raw_data(s.data));
end := begin + uintptr(len(s.data));
old_ptr := uintptr(old_memory);
if old_memory == s.prev_allocation && old_ptr & uintptr(alignment)-1 == 0 {
if old_ptr+uintptr(size) < end {
s.curr_offset = int(old_ptr-begin)+size;
return byte_slice(old_memory, size), .None;
}
}
ptr, err := default_temp_allocator_proc(allocator_data, .Alloc, size, alignment, old_memory, old_size, loc);
if err == .None {
copy(ptr, byte_slice(old_memory, old_size));
_, err = default_temp_allocator_proc(allocator_data, .Free, 0, alignment, old_memory, old_size, loc);
}
return ptr, err;
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory);
if set != nil {
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features};
}
return nil, nil;
case .Query_Info:
return nil, .None;
}
return nil, .None;
}
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
return Allocator{
procedure = default_temp_allocator_proc,
data = allocator,
};
}
@@ -0,0 +1,29 @@
//+build !windows
//+build !freestanding
package runtime
when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
// mem.nil_allocator reimplementation
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
return nil, .None;
}
default_allocator :: proc() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
}
} else {
// TODO(bill): reimplement these procedures in the os_specific stuff
import "core:os"
default_allocator_proc :: os.heap_allocator_proc;
default_allocator :: proc() -> Allocator {
return os.heap_allocator();
}
}
+17
View File
@@ -0,0 +1,17 @@
//+build freestanding
package runtime
// mem.nil_allocator reimplementation
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
return nil, .None;
}
default_allocator :: proc() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
}
@@ -0,0 +1,38 @@
//+build windows
package runtime
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
switch mode {
case .Alloc:
data, err = _windows_default_alloc(size, alignment);
case .Free:
_windows_default_free(old_memory);
case .Free_All:
// NOTE(tetra): Do nothing.
case .Resize:
data, err = _windows_default_resize(old_memory, old_size, size, alignment);
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory);
if set != nil {
set^ = {.Alloc, .Free, .Resize, .Query_Features};
}
case .Query_Info:
// Do nothing
}
return;
}
default_allocator :: proc() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
}
@@ -0,0 +1,196 @@
package runtime
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte {
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)};
}
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22);
Default_Temp_Allocator :: struct {
data: []byte,
curr_offset: int,
prev_allocation: rawptr,
backup_allocator: Allocator,
leaked_allocations: [dynamic][]byte,
}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator);
s.curr_offset = 0;
s.prev_allocation = nil;
s.backup_allocator = backup_allocator;
s.leaked_allocations.allocator = backup_allocator;
}
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
if s == nil {
return;
}
for ptr in s.leaked_allocations {
free(raw_data(ptr), s.backup_allocator);
}
delete(s.leaked_allocations);
delete(s.data, s.backup_allocator);
s^ = {};
}
@(private)
default_temp_allocator_alloc :: proc(s: ^Default_Temp_Allocator, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
size := size;
size = align_forward_int(size, alignment);
switch {
case s.curr_offset+size <= len(s.data):
start := uintptr(raw_data(s.data));
ptr := start + uintptr(s.curr_offset);
ptr = align_forward_uintptr(ptr, uintptr(alignment));
mem_zero(rawptr(ptr), size);
s.prev_allocation = rawptr(ptr);
offset := int(ptr - start);
s.curr_offset = offset + size;
return byte_slice(rawptr(ptr), size), .None;
case size <= len(s.data):
start := uintptr(raw_data(s.data));
ptr := align_forward_uintptr(start, uintptr(alignment));
mem_zero(rawptr(ptr), size);
s.prev_allocation = rawptr(ptr);
offset := int(ptr - start);
s.curr_offset = offset + size;
return byte_slice(rawptr(ptr), size), .None;
}
a := s.backup_allocator;
if a.procedure == nil {
a = context.allocator;
s.backup_allocator = a;
}
data, err := mem_alloc_bytes(size, alignment, a, loc);
if err != nil {
return data, err;
}
if s.leaked_allocations == nil {
s.leaked_allocations = make([dynamic][]byte, a);
}
append(&s.leaked_allocations, data);
// TODO(bill): Should leaks be notified about?
if logger := context.logger; logger.lowest_level <= .Warning {
if logger.procedure != nil {
logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc);
}
}
return data, .None;
}
@(private)
default_temp_allocator_free :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, loc := #caller_location) -> Allocator_Error {
if old_memory == nil {
return .None;
}
start := uintptr(raw_data(s.data));
end := start + uintptr(len(s.data));
old_ptr := uintptr(old_memory);
if s.prev_allocation == old_memory {
s.curr_offset = int(uintptr(s.prev_allocation) - start);
s.prev_allocation = nil;
return .None;
}
if start <= old_ptr && old_ptr < end {
// NOTE(bill): Cannot free this pointer but it is valid
return .None;
}
if len(s.leaked_allocations) != 0 {
for data, i in s.leaked_allocations {
ptr := raw_data(data);
if ptr == old_memory {
free(ptr, s.backup_allocator);
ordered_remove(&s.leaked_allocations, i);
return .None;
}
}
}
return .Invalid_Pointer;
// panic("invalid pointer passed to default_temp_allocator");
}
@(private)
default_temp_allocator_free_all :: proc(s: ^Default_Temp_Allocator, loc := #caller_location) {
s.curr_offset = 0;
s.prev_allocation = nil;
for data in s.leaked_allocations {
free(raw_data(data), s.backup_allocator);
}
clear(&s.leaked_allocations);
}
@(private)
default_temp_allocator_resize :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, old_size, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
begin := uintptr(raw_data(s.data));
end := begin + uintptr(len(s.data));
old_ptr := uintptr(old_memory);
if old_memory == s.prev_allocation && old_ptr & uintptr(alignment)-1 == 0 {
if old_ptr+uintptr(size) < end {
s.curr_offset = int(old_ptr-begin)+size;
return byte_slice(old_memory, size), .None;
}
}
data, err := default_temp_allocator_alloc(s, size, alignment, loc);
if err == .None {
copy(data, byte_slice(old_memory, old_size));
err = default_temp_allocator_free(s, old_memory, loc);
}
return data, err;
}
default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
s := (^Default_Temp_Allocator)(allocator_data);
if s.data == nil {
default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator());
}
switch mode {
case .Alloc:
data, err = default_temp_allocator_alloc(s, size, alignment, loc);
case .Free:
err = default_temp_allocator_free(s, old_memory, loc);
case .Free_All:
default_temp_allocator_free_all(s, loc);
case .Resize:
data, err = default_temp_allocator_resize(s, old_memory, old_size, size, alignment, loc);
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory);
if set != nil {
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features};
}
case .Query_Info:
// Nothing to give
}
return;
}
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
return Allocator{
procedure = default_temp_allocator_proc,
data = allocator,
};
}
+1 -1
View File
@@ -362,7 +362,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
curr := __dynamic_map_get_entry(h, fr.entry_index);
prev.next = curr.next;
}
if (fr.entry_index == m.entries.len-1) {
if fr.entry_index == m.entries.len-1 {
// NOTE(bill): No need to do anything else, just pop
} else {
old := __dynamic_map_get_entry(h, fr.entry_index);
-8
View File
@@ -22,7 +22,6 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
return;
}
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
context = default_context();
print_caller_location(Source_Code_Location{file, line, column, ""});
print_string(" Index ");
print_i64(i64(index));
@@ -35,7 +34,6 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
}
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
context = default_context();
print_caller_location(Source_Code_Location{file, line, column, ""});
print_string(" Invalid slice indices: ");
print_i64(i64(lo));
@@ -66,7 +64,6 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
return;
}
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
context = default_context();
print_caller_location(Source_Code_Location{file, line, column, ""});
print_string(" Invalid dynamic array values: ");
print_i64(i64(low));
@@ -86,7 +83,6 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
return;
}
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
context = default_context();
print_caller_location(Source_Code_Location{file, line, column, ""});
print_string(" Invalid type assertion from ");
print_typeid(from);
@@ -131,7 +127,6 @@ type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, colum
}
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
context = default_context();
actual := variant_type(from, from_data);
@@ -156,7 +151,6 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
return;
}
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
context = default_context();
print_caller_location(loc);
print_string(" Invalid slice length for make: ");
print_i64(i64(len));
@@ -171,7 +165,6 @@ make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #
return;
}
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
context = default_context();
print_caller_location(loc);
print_string(" Invalid dynamic array parameters for make: ");
print_i64(i64(len));
@@ -188,7 +181,6 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
return;
}
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
context = default_context();
print_caller_location(loc);
print_string(" Invalid map capacity for make: ");
print_i64(i64(cap));
+125 -102
View File
@@ -97,7 +97,7 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
if len < 0 {
return data;
}
memset(data, 0, len);
intrinsics.mem_zero(data, len);
return data;
}
@@ -105,27 +105,9 @@ mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil {
return dst;
}
// NOTE(bill): This _must_ be implemented like C's memmove
foreign _ {
when ODIN_USE_LLVM_API {
when size_of(rawptr) == 8 {
@(link_name="llvm.memmove.p0i8.p0i8.i64")
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
} else {
@(link_name="llvm.memmove.p0i8.p0i8.i32")
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
}
} else {
when size_of(rawptr) == 8 {
@(link_name="llvm.memmove.p0i8.p0i8.i64")
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
} else {
@(link_name="llvm.memmove.p0i8.p0i8.i32")
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
}
}
}
llvm_memmove(dst, src, len);
intrinsics.mem_copy(dst, src, len);
return dst;
}
@@ -133,27 +115,9 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r
if src == nil {
return dst;
}
// NOTE(bill): This _must_ be implemented like C's memcpy
foreign _ {
when ODIN_USE_LLVM_API {
when size_of(rawptr) == 8 {
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
} else {
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
}
} else {
when size_of(rawptr) == 8 {
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
} else {
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
}
}
}
llvm_memcpy(dst, src, len);
intrinsics.mem_copy_non_overlapping(dst, src, len);
return dst;
}
@@ -336,6 +300,9 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
}
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
complex64_eq :: #force_inline proc "contextless" (a, b: complex64) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
complex64_ne :: #force_inline proc "contextless" (a, b: complex64) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
@@ -343,6 +310,9 @@ complex128_eq :: #force_inline proc "contextless" (a, b: complex128) -> bool { r
complex128_ne :: #force_inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
quaternion64_eq :: #force_inline proc "contextless" (a, b: quaternion64) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion64_ne :: #force_inline proc "contextless" (a, b: quaternion64) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
quaternion128_eq :: #force_inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion128_ne :: #force_inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
@@ -429,90 +399,58 @@ string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
}
@(default_calling_convention = "none")
foreign {
@(link_name="llvm.sqrt.f32") _sqrt_f32 :: proc(x: f32) -> f32 ---
@(link_name="llvm.sqrt.f64") _sqrt_f64 :: proc(x: f64) -> f64 ---
}
abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 {
foreign {
@(link_name="llvm.fabs.f16") _abs :: proc "none" (x: f16) -> f16 ---
}
return _abs(x);
return -x if x < 0 else x;
}
abs_f32 :: #force_inline proc "contextless" (x: f32) -> f32 {
foreign {
@(link_name="llvm.fabs.f32") _abs :: proc "none" (x: f32) -> f32 ---
}
return _abs(x);
return -x if x < 0 else x;
}
abs_f64 :: #force_inline proc "contextless" (x: f64) -> f64 {
foreign {
@(link_name="llvm.fabs.f64") _abs :: proc "none" (x: f64) -> f64 ---
}
return _abs(x);
return -x if x < 0 else x;
}
min_f16 :: proc(a, b: f16) -> f16 {
foreign {
@(link_name="llvm.minnum.f16") _min :: proc "none" (a, b: f16) -> f16 ---
}
return _min(a, b);
min_f16 :: #force_inline proc "contextless" (a, b: f16) -> f16 {
return a if a < b else b;
}
min_f32 :: proc(a, b: f32) -> f32 {
foreign {
@(link_name="llvm.minnum.f32") _min :: proc "none" (a, b: f32) -> f32 ---
}
return _min(a, b);
min_f32 :: #force_inline proc "contextless" (a, b: f32) -> f32 {
return a if a < b else b;
}
min_f64 :: proc(a, b: f64) -> f64 {
foreign {
@(link_name="llvm.minnum.f64") _min :: proc "none" (a, b: f64) -> f64 ---
}
return _min(a, b);
min_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 {
return a if a < b else b;
}
max_f16 :: proc(a, b: f16) -> f16 {
foreign {
@(link_name="llvm.maxnum.f16") _max :: proc "none" (a, b: f16) -> f16 ---
}
return _max(a, b);
max_f16 :: #force_inline proc "contextless" (a, b: f16) -> f16 {
return a if a > b else b;
}
max_f32 :: proc(a, b: f32) -> f32 {
foreign {
@(link_name="llvm.maxnum.f32") _max :: proc "none" (a, b: f32) -> f32 ---
}
return _max(a, b);
max_f32 :: #force_inline proc "contextless" (a, b: f32) -> f32 {
return a if a > b else b;
}
max_f64 :: proc(a, b: f64) -> f64 {
foreign {
@(link_name="llvm.maxnum.f64") _max :: proc "none" (a, b: f64) -> f64 ---
}
return _max(a, b);
max_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 {
return a if a > b else b;
}
abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 {
r, i := real(x), imag(x);
return f16(_sqrt_f32(f32(r*r + i*i)));
return f16(intrinsics.sqrt(f32(r*r + i*i)));
}
abs_complex64 :: #force_inline proc "contextless" (x: complex64) -> f32 {
r, i := real(x), imag(x);
return _sqrt_f32(r*r + i*i);
return intrinsics.sqrt(r*r + i*i);
}
abs_complex128 :: #force_inline proc "contextless" (x: complex128) -> f64 {
r, i := real(x), imag(x);
return _sqrt_f64(r*r + i*i);
return intrinsics.sqrt(r*r + i*i);
}
abs_quaternion64 :: #force_inline proc "contextless" (x: quaternion64) -> f16 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return f16(_sqrt_f32(f32(r*r + i*i + j*j + k*k)));
return f16(intrinsics.sqrt(f32(r*r + i*i + j*j + k*k)));
}
abs_quaternion128 :: #force_inline proc "contextless" (x: quaternion128) -> f32 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f32(r*r + i*i + j*j + k*k);
return intrinsics.sqrt(r*r + i*i + j*j + k*k);
}
abs_quaternion256 :: #force_inline proc "contextless" (x: quaternion256) -> f64 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f64(r*r + i*i + j*j + k*k);
return intrinsics.sqrt(r*r + i*i + j*j + k*k);
}
@@ -662,19 +600,19 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
m = i & 0x007fffff;
if (e <= 0) {
if (e < -10) {
if e <= 0 {
if e < -10 {
return u16(s);
}
m = (m | 0x00800000) >> u32(1 - e);
if (m & 0x00001000) != 0 {
if m & 0x00001000 != 0 {
m += 0x00002000;
}
return u16(s | (m >> 13));
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
} else if e == 0xff - (127 - 15) {
if m == 0 {
return u16(s | 0x7c00); /* NOTE(bill): infinity */
} else {
/* NOTE(bill): NAN */
@@ -682,7 +620,7 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
return u16(s | 0x7c00 | m | i32(m == 0));
}
} else {
if (m & 0x00001000) != 0 {
if m & 0x00001000 != 0 {
m += 0x00002000;
if (m & 0x00800000) != 0 {
m = 0;
@@ -690,8 +628,8 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
}
}
if (e > 30) {
f := 1e12;
if e > 30 {
f := i64(1e12);
for j := 0; j < 10; j += 1 {
/* NOTE(bill): Cause overflow */
g := intrinsics.volatile_load(&f);
@@ -740,3 +678,88 @@ gnu_f2h_ieee :: proc "c" (value: f32) -> u16 {
extendhfsf2 :: proc "c" (value: u16) -> f32 {
return gnu_h2f_ieee(value);
}
@(link_name="__floattidf")
floattidf :: proc(a: i128) -> f64 {
DBL_MANT_DIG :: 53;
if a == 0 {
return 0.0;
}
a := a;
N :: size_of(i128) * 8;
s := a >> (N-1);
a = (a ~ s) - s;
sd: = N - intrinsics.count_leading_zeros(a); // number of significant digits
e := u32(sd - 1); // exponent
if sd > DBL_MANT_DIG {
switch sd {
case DBL_MANT_DIG + 1:
a <<= 1;
case DBL_MANT_DIG + 2:
// okay
case:
a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) |
i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0);
};
a |= i128((a & 4) != 0);
a += 1;
a >>= 2;
if a & (1 << DBL_MANT_DIG) != 0 {
a >>= 1;
e += 1;
}
} else {
a <<= u128(DBL_MANT_DIG - sd);
}
fb: [2]u32;
fb[1] = (u32(s) & 0x80000000) | // sign
((e + 1023) << 20) | // exponent
u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high
fb[1] = u32(a); // mantissa-low
return transmute(f64)fb;
}
@(link_name="__floattidf_unsigned")
floattidf_unsigned :: proc(a: u128) -> f64 {
DBL_MANT_DIG :: 53;
if a == 0 {
return 0.0;
}
a := a;
N :: size_of(u128) * 8;
sd: = N - intrinsics.count_leading_zeros(a); // number of significant digits
e := u32(sd - 1); // exponent
if sd > DBL_MANT_DIG {
switch sd {
case DBL_MANT_DIG + 1:
a <<= 1;
case DBL_MANT_DIG + 2:
// okay
case:
a = u128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) |
u128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0);
};
a |= u128((a & 4) != 0);
a += 1;
a >>= 2;
if a & (1 << DBL_MANT_DIG) != 0 {
a >>= 1;
e += 1;
}
} else {
a <<= u128(DBL_MANT_DIG - sd);
}
fb: [2]u32;
fb[1] = (0) | // sign
((e + 1023) << 20) | // exponent
u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high
fb[1] = u32(a); // mantissa-low
return transmute(f64)fb;
}
+2 -48
View File
@@ -1,5 +1,7 @@
package runtime
import "intrinsics"
@(link_name="__umodti3")
umodti3 :: proc "c" (a, b: u128) -> u128 {
r: u128 = ---;
@@ -85,51 +87,3 @@ fixdfti :: proc(a: u64) -> i128 {
}
}
@(default_calling_convention = "none")
foreign {
@(link_name="llvm.ctlz.i128") _clz_i128 :: proc(x: i128, is_zero_undef := false) -> i128 ---
}
@(link_name="__floattidf")
floattidf :: proc(a: i128) -> f64 {
DBL_MANT_DIG :: 53;
if a == 0 {
return 0.0;
}
a := a;
N :: size_of(i128) * 8;
s := a >> (N-1);
a = (a ~ s) - s;
sd: = N - _clz_i128(a); // number of significant digits
e := u32(sd - 1); // exponent
if sd > DBL_MANT_DIG {
switch sd {
case DBL_MANT_DIG + 1:
a <<= 1;
case DBL_MANT_DIG + 2:
// okay
case:
a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) |
i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0);
};
a |= i128((a & 4) != 0);
a += 1;
a >>= 2;
if a & (1 << DBL_MANT_DIG) != 0 {
a >>= 1;
e += 1;
}
} else {
a <<= u128(DBL_MANT_DIG - sd);
}
fb: [2]u32;
fb[1] = (u32(s) & 0x80000000) | // sign
((e + 1023) << 20) | // exponent
u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high
fb[1] = u32(a); // mantissa-low
return transmute(f64)fb;
}
+2 -48
View File
@@ -1,5 +1,7 @@
package runtime
import "intrinsics"
@(link_name="__umodti3")
umodti3 :: proc "c" (a, b: u128) -> u128 {
r: u128 = ---;
@@ -85,51 +87,3 @@ fixdfti :: proc(a: u64) -> i128 {
}
}
@(default_calling_convention = "none")
foreign {
@(link_name="llvm.ctlz.i128") _clz_i128 :: proc(x: i128, is_zero_undef := false) -> i128 ---
}
@(link_name="__floattidf")
floattidf :: proc(a: i128) -> f64 {
DBL_MANT_DIG :: 53;
if a == 0 {
return 0.0;
}
a := a;
N :: size_of(i128) * 8;
s := a >> (N-1);
a = (a ~ s) - s;
sd: = N - _clz_i128(a); // number of significant digits
e := u32(sd - 1); // exponent
if sd > DBL_MANT_DIG {
switch sd {
case DBL_MANT_DIG + 1:
a <<= 1;
case DBL_MANT_DIG + 2:
// okay
case:
a = i128(u128(a) >> u128(sd - (DBL_MANT_DIG+2))) |
i128(u128(a) & (~u128(0) >> u128(N + DBL_MANT_DIG+2 - sd)) != 0);
};
a |= i128((a & 4) != 0);
a += 1;
a >>= 2;
if a & (1 << DBL_MANT_DIG) != 0 {
a >>= 1;
e += 1;
}
} else {
a <<= u128(DBL_MANT_DIG - sd);
}
fb: [2]u32;
fb[1] = (u32(s) & 0x80000000) | // sign
((e + 1023) << 20) | // exponent
u32((u64(a) >> 32) & 0x000FFFFF); // mantissa-high
fb[1] = u32(a); // mantissa-low
return transmute(f64)fb;
}
+4
View File
@@ -1,3 +1,7 @@
package runtime
_OS_Errno :: distinct int;
os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
return _os_write(data);
}
+1 -5
View File
@@ -6,12 +6,8 @@ import "core:os"
// TODO(bill): reimplement `os.write` so that it does not rely on package os
// NOTE: Use os_specific_linux.odin, os_specific_darwin.odin, etc
os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
context = default_context();
n, err := os.write(os.stderr, data);
return int(n), _OS_Errno(err);
}
current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id();
}
+1 -5
View File
@@ -2,10 +2,6 @@
package runtime
// TODO(bill): reimplement `os.write`
os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
return 0, -1;
}
current_thread_id :: proc "contextless" () -> int {
return 0;
}
+49 -85
View File
@@ -1,6 +1,9 @@
//+private
//+build windows
package runtime
import "intrinsics"
foreign import kernel32 "system:Kernel32.lib"
@(private="file")
@@ -14,9 +17,6 @@ foreign kernel32 {
WriteFile :: proc(hFile: rawptr, lpBuffer: rawptr, nNumberOfBytesToWrite: u32, lpNumberOfBytesWritten: ^u32, lpOverlapped: rawptr) -> b32 ---
GetLastError :: proc() -> u32 ---
// current_thread_id
GetCurrentThreadId :: proc() -> u32 ---
// default_allocator
GetProcessHeap :: proc() -> rawptr ---
HeapAlloc :: proc(hHeap: rawptr, dwFlags: u32, dwBytes: uint) -> rawptr ---
@@ -24,7 +24,7 @@ foreign kernel32 {
HeapFree :: proc(hHeap: rawptr, dwFlags: u32, lpMem: rawptr) -> b32 ---
}
os_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) {
_os_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) #no_bounds_check {
if len(data) == 0 {
return 0, 0;
}
@@ -58,11 +58,6 @@ os_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) {
return;
}
current_thread_id :: proc "contextless" () -> int {
return int(GetCurrentThreadId());
}
heap_alloc :: proc "contextless" (size: int) -> rawptr {
HEAP_ZERO_MEMORY :: 0x00000008;
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uint(size));
@@ -86,89 +81,58 @@ heap_free :: proc "contextless" (ptr: rawptr) {
HeapFree(GetProcessHeap(), 0, ptr);
}
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
//
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
// Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
// padding. We also store the original pointer returned by heap_alloc right before
// the pointer we return to the user.
//
//
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
// Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
// padding. We also store the original pointer returned by heap_alloc right before
// the pointer we return to the user.
//
aligned_alloc :: proc "contextless" (size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, Allocator_Error) {
a := max(alignment, align_of(rawptr));
space := size + a - 1;
allocated_mem: rawptr;
if old_ptr != nil {
original_old_ptr := ptr_offset((^rawptr)(old_ptr), -1)^;
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr));
} else {
allocated_mem = heap_alloc(space+size_of(rawptr));
}
aligned_mem := rawptr(ptr_offset((^u8)(allocated_mem), size_of(rawptr)));
ptr := uintptr(aligned_mem);
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a);
diff := int(aligned_ptr - ptr);
if (size + diff) > space {
return nil, .Out_Of_Memory;
}
aligned_mem = rawptr(aligned_ptr);
ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem;
return byte_slice(aligned_mem, size), nil;
}
aligned_free :: proc "contextless" (p: rawptr) {
if p != nil {
heap_free(ptr_offset((^rawptr)(p), -1)^);
}
}
aligned_resize :: proc "contextless" (p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, Allocator_Error) {
if p == nil {
return nil, nil;
}
return aligned_alloc(new_size, new_alignment, p);
}
switch mode {
case .Alloc:
return aligned_alloc(size, alignment);
case .Free:
aligned_free(old_memory);
case .Free_All:
// NOTE(tetra): Do nothing.
case .Resize:
if old_memory == nil {
return aligned_alloc(size, alignment);
}
return aligned_resize(old_memory, old_size, size, alignment);
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory);
if set != nil {
set^ = {.Alloc, .Free, .Resize, .Query_Features};
}
return nil, nil;
case .Query_Info:
_windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, Allocator_Error) {
if size == 0 {
_windows_default_free(old_ptr);
return nil, nil;
}
return nil, nil;
a := max(alignment, align_of(rawptr));
space := size + a - 1;
allocated_mem: rawptr;
if old_ptr != nil {
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^;
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr));
} else {
allocated_mem = heap_alloc(space+size_of(rawptr));
}
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)));
ptr := uintptr(aligned_mem);
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a);
diff := int(aligned_ptr - ptr);
if (size + diff) > space {
return nil, .Out_Of_Memory;
}
aligned_mem = rawptr(aligned_ptr);
intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem;
return byte_slice(aligned_mem, size), nil;
}
default_allocator :: proc() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
_windows_default_alloc :: proc "contextless" (size, alignment: int) -> ([]byte, Allocator_Error) {
return _windows_default_alloc_or_resize(size, alignment, nil);
}
_windows_default_free :: proc "contextless" (ptr: rawptr) {
if ptr != nil {
heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^);
}
}
_windows_default_resize :: proc "contextless" (p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, Allocator_Error) {
return _windows_default_alloc_or_resize(new_size, new_alignment, p);
}
+3 -3
View File
@@ -86,7 +86,7 @@ print_encoded_rune :: proc "contextless" (r: rune) {
print_byte('\'');
}
print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) {
print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check {
RUNE_SELF :: 0x80;
if r < RUNE_SELF {
@@ -98,7 +98,7 @@ print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) {
}
print_u64 :: proc "contextless" (x: u64) {
print_u64 :: proc "contextless" (x: u64) #no_bounds_check {
digits := _INTEGER_DIGITS;
a: [129]byte;
@@ -115,7 +115,7 @@ print_u64 :: proc "contextless" (x: u64) {
}
print_i64 :: proc "contextless" (x: i64) {
print_i64 :: proc "contextless" (x: i64) #no_bounds_check {
digits := _INTEGER_DIGITS;
b :: i64(10);
+9 -5
View File
@@ -1,18 +1,22 @@
package runtime
import "core:sys/es"
@(link_name="memset")
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
return es.CRTmemset(ptr, val, len);
addr := 0x1000 + 196 * size_of(int);
fp := (rawptr(((^uintptr)(uintptr(addr)))^));
return ((proc "c" (rawptr, i32, int) -> rawptr)(fp))(ptr, val, len);
}
@(link_name="memmove")
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
return es.CRTmemmove(dst, src, len);
addr := 0x1000 + 195 * size_of(int);
fp := (rawptr(((^uintptr)(uintptr(addr)))^));
return ((proc "c" (rawptr, rawptr, int) -> rawptr)(fp))(dst, src, len);
}
@(link_name="memcpy")
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
return es.CRTmemcpy(dst, src, len);
addr := 0x1000 + 194 * size_of(int);
fp := (rawptr(((^uintptr)(uintptr(addr)))^));
return ((proc "c" (rawptr, rawptr, int) -> rawptr)(fp))(dst, src, len);
}
+5 -29
View File
@@ -1,41 +1,17 @@
package runtime
@(default_calling_convention="none")
foreign {
@(link_name="llvm.cttz.i8") _ctz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.cttz.i16") _ctz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.cttz.i32") _ctz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.cttz.i64") _ctz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
}
_ctz :: proc{
_ctz_u8,
_ctz_u16,
_ctz_u32,
_ctz_u64,
};
@(default_calling_convention="none")
foreign {
@(link_name="llvm.ctlz.i8") _clz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.ctlz.i16") _clz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.ctlz.i32") _clz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.ctlz.i64") _clz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
}
_clz :: proc{
_clz_u8,
_clz_u16,
_clz_u32,
_clz_u64,
};
import "intrinsics"
udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
_ctz :: intrinsics.count_trailing_zeros;
_clz :: intrinsics.count_leading_zeros;
n := transmute([2]u64)a;
d := transmute([2]u64)b;
q, r: [2]u64 = ---, ---;
sr: u32 = 0;
low :: ODIN_ENDIAN == "big" ? 1 : 0;
low :: 1 when ODIN_ENDIAN == "big" else 0;
high :: 1 - low;
U64_BITS :: 8*size_of(u64);
U128_BITS :: 8*size_of(u128);
+2 -2
View File
@@ -27,12 +27,12 @@ map_values :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (values:
return;
}
Map_Entry :: struct(Key, Value: typeid) {
Map_Entry :: struct($Key, $Value: typeid) {
key: Key,
value: Value,
}
Map_Entry_Info :: struct(Key, Value: typeid) {
Map_Entry_Info :: struct($Key, $Value: typeid) {
hash: uintptr,
key: Key,
value: Value,
+7 -7
View File
@@ -16,9 +16,9 @@ _digit_value :: proc(r: rune) -> int {
ri := int(r);
v: int = 16;
switch r {
case '0'..'9': v = ri-'0';
case 'a'..'z': v = ri-'a'+10;
case 'A'..'Z': v = ri-'A'+10;
case '0'..='9': v = ri-'0';
case 'a'..='z': v = ri-'a'+10;
case 'A'..='Z': v = ri-'A'+10;
}
return v;
}
@@ -557,9 +557,9 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
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;
}
@@ -597,7 +597,7 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool
case '"': r = '"';
case '\'': r = '\'';
case '0'..'7':
case '0'..='7':
v := int(c-'0');
if len(s) < 2 {
return;
+3 -3
View File
@@ -221,7 +221,7 @@ pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
}
@(private, static)
@(private)
DIGITS_LOWER := "0123456789abcdefx";
write_quoted_string :: proc{
@@ -314,9 +314,9 @@ write_escaped_rune_writer :: proc(w: io.Writer, r: rune, quote: byte, html_safe
is_printable :: proc(r: rune) -> bool {
if r <= 0xff {
switch r {
case 0x20..0x7e:
case 0x20..=0x7e:
return true;
case 0xa1..0xff: // ¡ through ÿ except for the soft hyphen
case 0xa1..=0xff: // ¡ through ÿ except for the soft hyphen
return r != 0xad; //
}
}

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