Compare commits

..

237 Commits

Author SHA1 Message Date
Ginger Bill 49d337c830 v0.6.2; Use Ada_Case for types 2017-08-03 21:21:56 +01:00
Ginger Bill 294092979e Update build.bat 2017-08-01 21:38:06 +01:00
Ginger Bill c454ede184 v0.6.1a 2017-08-01 17:30:26 +01:00
Ginger Bill d854c5003c Fix minor errors for *nix 2017-08-01 17:28:49 +01:00
Ginger Bill 66d8776b83 v0.6.1 2017-08-01 15:18:37 +01:00
Ginger Bill ba6ecf35cf Disable threading on *nix for the time being 2017-08-01 15:09:43 +01:00
Ginger Bill 10cc9cf661 Add mutexes to string buffer allocator uses 2017-08-01 14:24:40 +01:00
Ginger Bill 2db971eedd Use pthread mutex 2017-08-01 13:49:12 +01:00
Ginger Bill 1775e80b41 HACK: Ignore Mutex check 2017-07-31 23:18:21 +01:00
Ginger Bill e4a93619db Update gb.h 2017-07-31 12:17:53 +01:00
Ginger Bill 4d14b3bcb4 Update remove_temp_files 2017-07-31 12:15:20 +01:00
Ginger Bill 9f4f5f9346 Add -keep-temp-files option 2017-07-31 12:06:04 +01:00
Ginger Bill 0fae31fb54 Extra type safety; Fix typos 2017-07-31 11:36:00 +01:00
Ginger Bill 8987a6630c v0.6.0 2017-07-30 22:26:22 +01:00
Ginger Bill 10ff8e0426 Fix ir for TypeInfo.Map 2017-07-30 20:17:25 +01:00
Ginger Bill a0ae02168a Update add_type_info_type to ignore polymorphic types 2017-07-30 20:13:23 +01:00
Ginger Bill a3c1ac2030 Speed up llvm ir printing; Use CRITICAL_SECTION for Mutex on windows 2017-07-30 19:47:37 +01:00
Ginger Bill 629b248f53 Parallelization of the Parser
~66% reduction (unoptimized build)
~30% reduction (optimized build)
2017-07-30 19:01:02 +01:00
Ginger Bill 62a72f0163 transmute(type)x; Minor code clean up 2017-07-30 14:52:42 +01:00
Ginger Bill 655931f0ea Minor Simplification of threading demo 2017-07-29 15:18:36 +01:00
Ginger Bill ca36fabfc0 Remove dead code for the "fixed" map idea 2017-07-29 14:43:42 +01:00
Ginger Bill 7bd62481ad Fix nil assignment to unions 2017-07-29 14:23:34 +01:00
Ginger Bill fbd27d7c45 Fix map internal type generation 2017-07-29 13:56:45 +01:00
Ginger Bill 3546391311 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-29 13:01:28 +01:00
Ginger Bill 24c812115e Remove empty union check on array types; Fix overflowing error printing 2017-07-29 13:01:17 +01:00
gingerBill 28be0ad69b Fix IR print bug for empty structs; 2017-07-28 11:35:01 +01:00
gingerBill f0980c0a98 Fix import name exportation bug; Fix procedure type printing 2017-07-24 07:57:09 +01:00
Ginger Bill 1df4aa90ce Fix struct parameter bugs 2017-07-21 15:25:58 +01:00
Ginger Bill 6b3cf051f8 Fix math.odin, again 2017-07-21 12:39:05 +01:00
Ginger Bill 4ecd6e592b Fix missing semicolons in math.odin 2017-07-21 10:37:49 +01:00
Ginger Bill dbddec33c8 Internal changes; thread.odin for windows only 2017-07-20 23:57:56 +01:00
Ginger Bill 401a5955a4 Fix minor check on vector types 2017-07-20 19:55:54 +01:00
Ginger Bill 9a3b4167bb Fix polymorphic element types usage; Empty union as opaque type 2017-07-20 19:40:51 +01:00
Ginger Bill 13bc6eeea4 Make fields et al an Array rather than a raw pointer 2017-07-20 15:32:34 +01:00
Ginger Bill 2da18b6d33 Change internals from Record to Struct 2017-07-20 15:23:13 +01:00
Ginger Bill 6d37ed12d2 Update internals of a Union and Tuple 2017-07-20 15:17:04 +01:00
Ginger Bill eab23cd5b7 Fix parsing bug with procedure types in return values 2017-07-19 22:34:50 +01:00
Ginger Bill d233706a2d Fix minor parsing bug with procedure return types 2017-07-19 22:17:57 +01:00
Ginger Bill f1ab17ed4e type_info_of; enum_value_to_string and string_to_enum_value 2017-07-19 14:01:56 +01:00
Ginger Bill 6113164211 Change union layout to store type info rather than an integer; ternary expression for types with constant condition 2017-07-19 12:15:21 +01:00
Ginger Bill 4db462a703 Fix copy 2017-07-18 20:39:53 +01:00
Ginger Bill a22c6d6c0c Fix parsing error for compound literals 2017-07-18 19:57:30 +01:00
Ginger Bill 59fb7b020a Merge raw_union into struct as a memory layout tag #raw_union 2017-07-18 19:24:45 +01:00
Ginger Bill 65f079ebc4 Remove atomic, ++, and -- 2017-07-18 18:58:41 +01:00
Ginger Bill d16aa79492 General specialization for polymorphic parameters 2017-07-18 18:05:41 +01:00
Ginger Bill 5af0acc4af Disallow default struct values for any; new_clone 2017-07-18 16:02:01 +01:00
Ginger Bill a459364de3 Ignore missing default values for struct literals at the end 2017-07-18 15:32:34 +01:00
Ginger Bill 277ef1a68f Allow undefined --- as a struct field default value. 2017-07-18 15:09:24 +01:00
Ginger Bill 193c7c82c8 Default struct field values 2017-07-18 14:56:07 +01:00
Ginger Bill f7d8ba408c Fix some preload bugs. 2017-07-18 11:42:16 +01:00
Ginger Bill 9a8759efef Polymorphic type specialization for procedures 2017-07-17 15:08:36 +01:00
Ginger Bill 054948e701 Basic procedure type parameter specialization 2017-07-16 15:00:16 +01:00
Ginger Bill 1c5ddd65b4 Rudimentary support for parametric polymorphic types 2017-07-13 22:35:00 +01:00
Ginger Bill b8697fb4ed Change precedence order for types e.g. ^T(x) == ^(T(x)) 2017-07-13 16:20:07 +01:00
Ginger Bill 03570275c1 Fix issue #78 and have a better error message. 2017-07-13 11:35:01 +01:00
Ginger Bill b5587f1937 Fix aliasing of overloaded procedures from other scopes 2017-07-11 20:54:38 +01:00
Ginger Bill c4c6975f1b cast(Type)expr; Fix overloaded procedure determination on assignment 2017-07-11 14:40:27 +01:00
Ginger Bill 0be0fb2a57 Nested when statements within records 2017-07-10 23:47:22 +01:00
Ginger Bill 115e6e7f9e Update demo for both subtyping and union based Entity 2017-07-10 23:28:53 +01:00
Ginger Bill 3868a9a0f0 Clean up _preload.odin types 2017-07-10 23:15:41 +01:00
Ginger Bill ba5050ac7c Compiler Internal Changes: TypeRecord_Union -> Type_Union 2017-07-10 22:59:23 +01:00
Ginger Bill d936ca1ea0 Compiler internal change: TypeRecord_Enum -> Type_Enum 2017-07-10 22:42:58 +01:00
Ginger Bill fd8c4d58bb union type allow for any types and removes common fields 2017-07-10 22:32:21 +01:00
Ginger Bill ce4b7b8b7d Nested record declarations 2017-07-10 20:39:42 +01:00
Ginger Bill 069a47220e Make record semicolon syntax more consistent 2017-07-10 14:52:58 +01:00
Ginger Bill 66e4aaffc5 Use semicolons as field delimiters in records 2017-07-10 13:49:50 +01:00
Ginger Bill 81336b58cb "Fix" printing of embedded any to prevent recursion 2017-07-10 10:37:51 +01:00
Ginger Bill b201670f7a Fix _preload.odin; Add for in without parameters; Change sync.Mutex for windows 2017-07-08 23:13:57 +01:00
Ginger Bill 4b051a0d3b .. half closed range; ... open range; ... variadic syntax 2017-07-07 23:42:43 +01:00
Ginger Bill 45353465a6 Add sort.odin 2017-07-07 22:26:55 +01:00
Ginger Bill c63cb98019 Fix else do 2017-07-07 17:50:45 +01:00
Ginger Bill 773cf5ca08 Add -show-timings; Clean up polymorphic procedure code a bit 2017-07-07 15:26:49 +01:00
Ginger Bill 2db03cb4a5 Fix aprint* bug; NULL -> nullptr; Better error messages for overloaded functions 2017-07-06 22:43:55 +01:00
Ginger Bill eed873c6ec Add free for maps (a previous oversight) 2017-07-05 13:51:25 +01:00
Ginger Bill 3d2d461867 Replace many built-in procedures with user-level procedures 2017-07-04 23:52:00 +01:00
Ginger Bill 36392d658e Fix demo.odin 2017-07-04 22:43:38 +01:00
Ginger Bill 82696179e8 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-04 22:42:41 +01:00
Ginger Bill 188bc28f6a Allow for overloading of polymorphic procedures 2017-07-04 22:42:25 +01:00
Ginger Bill 240da5c8e0 Allow aliasing of aliases 2017-07-04 16:06:08 +01:00
Ginger Bill 689a0c0b49 *_of as keyords; Allow constant aliasing for user/built-in procedures, import names, and library names 2017-07-04 11:23:48 +01:00
Ginger Bill bc16b290ba Disable polymorphic overloading in the global scope
TODO: Figure out why it does not work in the global scope
2017-07-02 22:08:39 +01:00
Ginger Bill 96d32680fe Allow overloading of polymorphic procedures 2017-07-02 10:45:22 +01:00
Ginger Bill d782b3d21d Fix do on for loops 2017-07-01 11:53:01 +01:00
Ginger Bill ed089b44b9 do keyword for inline statements instead of blocks 2017-07-01 11:38:44 +01:00
Ginger Bill 33f4af2e19 Fix demo 2017-06-29 21:01:07 +01:00
Ginger Bill 69f7382eec Implicit parametric polymorphic procedures 2017-06-29 20:56:18 +01:00
Ginger Bill 7e3293fc20 Fix odin version printing 2017-06-29 16:08:30 +01:00
Ginger Bill e4a8283327 Remove Type
What was I thinking?!
2017-06-29 15:48:07 +01:00
Ginger Bill 001baf4419 Add Type -- Runtime type for comparing types (similar to TypeInfo but simpler) 2017-06-29 15:13:41 +01:00
Ginger Bill d167290b28 Make AstNodeIdent a struct wrapping its Token 2017-06-29 12:11:50 +01:00
Ginger Bill f4879d4723 Update procedure names and extend demo.odin 2017-06-29 11:25:05 +01:00
Ginger Bill fd81c06c35 Remove var and const keywords; Fix default parameter syntax 2017-06-28 23:55:40 +01:00
Ginger Bill 94afcec757 :: style procedure declarations; remove old parsing code 2017-06-28 23:47:06 +01:00
Ginger Bill 4f28e9e1fb Remove type prefix declarations 2017-06-28 23:23:10 +01:00
Ginger Bill 0622509807 Disable var and const declarations 2017-06-28 23:17:20 +01:00
Ginger Bill 9ca2246bac Basic allowance for := and :: 2017-06-28 22:38:04 +01:00
Ginger Bill 647e2cafd7 Fix expand_to_tuple 2017-06-27 22:47:19 +01:00
Ginger Bill 5df854fcef Fixed demo 2017-06-27 15:58:53 +01:00
Ginger Bill 260089431e Write demo for v0.5.0 2017-06-26 21:34:54 +01:00
Ginger Bill d0d8da8c08 Revert demo 2017-06-26 19:42:32 +01:00
Ginger Bill d1365b3466 Fix poly-procs for variadic calls 2017-06-26 19:24:04 +01:00
Ginger Bill c949ca2a5c Allow for named arguments for polymorphic procedures 2017-06-26 18:20:24 +01:00
Ginger Bill d974b29f67 Reduce excessive node cloning on para-poly checking and fix scope bug 2017-06-26 14:39:51 +01:00
Ginger Bill cc7316bb35 Fix IR printing for para-poly procedures 2017-06-26 14:16:16 +01:00
Ginger Bill a0d8dcd974 Remove let 2017-06-26 13:59:15 +01:00
Ginger Bill c642e326ce Undef value --- (for setting a value to be uninitialized/undefined) 2017-06-26 11:57:26 +01:00
Ginger Bill 362a118782 Remove "overloading" bug of para-poly-procs 2017-06-25 23:41:46 +01:00
Ginger Bill 3ab481df17 new as a user-level procedure 2017-06-25 22:31:30 +01:00
Ginger Bill 4e7150b470 Allow nested para-poly procedures 2017-06-25 22:29:23 +01:00
Ginger Bill 1ced92be47 Rudimentary para-poly procedures 2017-06-25 22:15:30 +01:00
Ginger Bill 15dbea6899 Generic procedures generate types on use 2017-06-25 19:41:07 +01:00
Ginger Bill c4081393c1 Fix typo for some built-in procedures 2017-06-25 17:36:10 +01:00
Ginger Bill 1d81b73df9 Basic command line flags: e.g. -opt=0 2017-06-24 22:58:50 +01:00
Ginger Bill 18f885efab expand_to_tuple 2017-06-24 20:39:37 +01:00
Ginger Bill bba088bee7 Use UTF-8 command line on windows 2017-06-24 11:42:49 +01:00
Ginger Bill 6cbb6bef0b Wrap hashing functions 2017-06-22 16:14:02 +01:00
Ginger Bill 8744c60563 Clean up code for return statements, slightly 2017-06-22 13:47:50 +01:00
Ginger Bill 8197c02dcf Default result values for procedure types; Named result values in return statements 2017-06-22 01:14:45 +01:00
Ginger Bill 9faf0020cc Amend Checker API 2017-06-21 21:46:27 +01:00
Ginger Bill 53075e2570 Update old demos 2017-06-21 21:20:26 +01:00
Ginger Bill 264ca00db7 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-06-21 17:49:05 +01:00
Ginger Bill 6b65ef6d88 Fix compilation bug on Linux 2017-06-21 17:48:50 +01:00
Ginger Bill 5957d7f7be Implicit Parameter Passing based context system (replacing Thread Local Storage (TLS) approach) 2017-06-20 12:38:05 +01:00
Ginger Bill 35c102137f Compiler compiles for x86 (doesn't work properly) 2017-06-19 18:49:11 +01:00
Ginger Bill 5427d14416 Code will compile as 32 bit but will causes errors in the linker on Windows 2017-06-19 15:55:09 +01:00
Ginger Bill 178236d1ff Barebones layout for the documentation declarations 2017-06-18 23:41:13 +01:00
Ginger Bill 736c880ba9 Add docs.cpp 2017-06-18 23:18:15 +01:00
Ginger Bill 126f7aa892 Begin work on documentation generation 2017-06-18 23:16:57 +01:00
Ginger Bill 2957f007e3 Fix #location for anonymous procedures 2017-06-18 17:35:27 +01:00
Ginger Bill 04501c93fe Implement assert and panic in user side code
Removes 2 more built-in procedures!
2017-06-18 17:25:28 +01:00
Ginger Bill 4236519b84 #location(..) and #call_location 2017-06-18 14:36:06 +01:00
Ginger Bill e4944b4f2e Fix error reporting for foreign blocks 2017-06-17 20:03:52 +01:00
Ginger Bill 2deb2f8eeb Declaration grouping uses () rather than {}; Fix some problem with compilation on *nix 2017-06-17 12:01:53 +01:00
Ginger Bill 3fa398ec43 Add extra check for bodiless procedures 2017-06-15 21:36:29 +01:00
Ginger Bill 1851674b50 Code use API rather than raw CheckerInfo; begin work on generic procedures 2017-06-15 18:11:58 +01:00
Ginger Bill c5ef5279d4 Add foreign variables 2017-06-15 14:42:08 +01:00
Ginger Bill d3c24d159f Merge size_of and size_of_val et al. 2017-06-15 12:25:53 +01:00
Ginger Bill 23f9f9064e Add CheckerInfo API functions 2017-06-15 12:14:56 +01:00
Ginger Bill a134307dcd Fix issue #72 - 128-bit literal corruption 2017-06-14 14:58:48 +01:00
Ginger Bill c3b510c2d9 C-style c_varargs (Not heavily tested) 2017-06-13 21:00:42 +01:00
Ginger Bill e7fc24e48c Fix compilation error for Invalid EntityKind 2017-06-13 18:04:22 +01:00
Ginger Bill 6a88dc322a Declaration grouping uses braces rather than parentheses 2017-06-13 15:04:23 +01:00
Ginger Bill 6b464e3558 Update README.md 2017-06-12 21:41:14 +01:00
Ginger Bill 76b0c7b765 "Revert" to older demo 2017-06-12 21:27:53 +01:00
Ginger Bill 91857e8f16 Remove redundant paths in parsing 2017-06-12 21:25:47 +01:00
Ginger Bill ccda456c0a foreign blocks for procedures 2017-06-12 21:21:18 +01:00
Ginger Bill 83bad13e9e Update default field value syntax; Use more declaration groupings 2017-06-12 18:38:27 +01:00
Ginger Bill e6a206a430 Check for empty generic declaration list 2017-06-12 16:58:25 +01:00
Ginger Bill f52a1e4ded Fix IR bug for TypeSpec 2017-06-12 16:47:07 +01:00
Ginger Bill a8e458339b foreign_library allow for Pascal-style grouping 2017-06-12 16:26:51 +01:00
Ginger Bill 6b5e9aec8e Pascal style declaration grouping with () 2017-06-12 15:42:21 +01:00
Ginger Bill 2ab0d97573 import and import_load as keywords; Fix procedure literal call trick 2017-06-12 14:19:12 +01:00
Ginger Bill 0c05fc1432 Prefix type and let to replace immutable 2017-06-12 12:56:47 +01:00
Ginger Bill 33eeb58521 Prefix proc syntax 2017-06-12 12:34:55 +01:00
Ginger Bill 8fafdb185c Remove := with var and :: with const 2017-06-12 11:48:12 +01:00
Ginger Bill c2c935ba81 Fix trailing default argument checking 2017-06-11 20:52:54 +01:00
Ginger Bill 2d73c8868b Make default arguments for records invalid syntax 2017-06-11 19:01:36 +01:00
gingerBill b95bb1286b Merge pull request #70 from ThisDrunkDane/master
Add some WM_*, some WS_* and map_virtual_key
2017-06-11 18:54:30 +01:00
Mikkel Hjortshoej 4237c8ec30 Merge branch 'master' of github.com:gingerBill/Odin 2017-06-11 19:53:44 +02:00
Ginger Bill 49b4b39055 Minor change for overloaded procedures 2017-06-11 18:53:20 +01:00
Mikkel Hjortshoej bf15fea135 Merge branch 'master' of github.com:gingerBill/Odin 2017-06-11 19:47:57 +02:00
Mikkel Hjortshoej 47c03e376d Merge branch 'master' of github.com:gingerBill/Odin 2017-06-11 19:47:05 +02:00
Ginger Bill 1cabfac36c Update README.md 2017-06-11 18:46:59 +01:00
Mikkel Hjortshoej 8e32276283 Added a bunch of VM_* and map_virtual_key 2017-06-11 19:46:55 +02:00
Ginger Bill 366b306df0 Default parameters for procedures 2017-06-11 18:38:30 +01:00
Ginger Bill 4bf1f798f5 Allow for ignoring named procedural call arguments with _ 2017-06-11 17:41:55 +01:00
Ginger Bill b2fdb69b4d Named procedure calls 2017-06-11 12:01:40 +01:00
Ginger Bill af2736daec Fix bit field bug 2017-06-08 16:29:05 +01:00
Ginger Bill 5cad7d44a6 Use templated Map for extra type safety 2017-06-08 13:26:48 +01:00
Ginger Bill 2b96be0ae8 Remove unnecessary typedef usage 2017-06-08 13:08:39 +01:00
Ginger Bill 2a89d8021c Use templated Array with bounds checking 2017-06-08 12:54:52 +01:00
Ginger Bill 13deb4706c Update String to use overloading 2017-06-08 12:37:07 +01:00
Ginger Bill 9b61adb97d Build as C++ 2017-06-08 12:03:40 +01:00
Ginger Bill 333924cce1 v0.3 Release 2017-06-08 11:35:22 +01:00
Ginger Bill 574b82c0c7 v0.3.0 2017-06-07 22:09:16 +01:00
Ginger Bill f60c772c11 Make rune a basic type and not an alias; Remove byte 2017-06-06 23:54:33 +01:00
Ginger Bill 107740ca5e Fix issue #69 for fmt.printf padding 2017-06-06 10:02:53 +01:00
gingerBill 88b990eb63 Merge pull request #53 from ghost/master
Fix link time error about missing -fPIC flag
2017-06-06 09:47:40 +01:00
Ginger Bill d2e7d730ac Fix key generation for constant strings in IR 2017-06-05 23:06:15 +01:00
Ginger Bill 817e4b663e Add murmurhash3.c 2017-06-05 22:52:56 +01:00
Ginger Bill 214bb73454 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-06-05 18:01:57 +01:00
Ginger Bill eba2c74bff Allow 128 bit map keys 2017-06-05 18:01:41 +01:00
gingerBill 7c5e6c808b Merge pull request #68 from ThisDrunkDane/master
Added extra sys/windows.odin stuff
2017-06-05 15:18:04 +01:00
Ginger Bill ebe5beaafd Allow using on bit fields 2017-06-04 11:53:33 +01:00
Ginger Bill 029a6095d9 Fix enum printing bug 2017-06-04 00:20:16 +01:00
Ginger Bill 2c0e59ae06 bit_field; Lexical sugar operators ≠ ≤ ≥
Example below:
// See: https://en.wikipedia.org/wiki/Bit_field
BoxProps :: bit_field {
	opaque        : 1,
	fill_colour   : 3,
	_             : 4,
	show_border   : 1,
	border_colour : 3,
	border_style  : 2,
	_             : 2,
	width         : 4,
	height        : 4,
	_             : 8,
}
2017-06-03 22:27:23 +01:00
Ginger Bill 9d1a4c304a Remove Quat from math.odin 2017-06-01 15:12:54 +01:00
Ginger Bill 13b8a1e348 Remove quaternion128 and quaternion256 as core types 2017-06-01 14:52:33 +01:00
Ginger Bill 0d4945dc87 Implement u128/i128 features; Add bits.odin 2017-06-01 14:23:46 +01:00
Mikkel Hjortshoej e0b9c4a275 Added extra sys/windows.odin stuff
- Added PM_NOREMOVE
	- Added PM_NOYIELD
	- Added get_message_a
	- Added post_message_a
2017-06-01 00:05:33 +02:00
Ginger Bill fec6df65b3 Use 128-bit integers for ExactValue integers 2017-05-30 15:23:01 +01:00
Ginger Bill 78494e84d5 Remove some asserts in timings.c 2017-05-29 19:41:13 +01:00
Ginger Bill 60d7c833c0 Fix unary expression type check 2017-05-28 21:56:40 +01:00
Ginger Bill 98dbbf11f3 Fix procedure overloading distinguishing 2017-05-28 18:51:42 +01:00
Ginger Bill f4924e39d4 Fix printing of struct literals with custom alignment 2017-05-28 16:11:19 +01:00
Ginger Bill 826e05c96e Convert windows.odin to the new naming convention 2017-05-28 16:08:29 +01:00
Ginger Bill d3f63e5903 Change label syntax for for and match from #label name to name: 2017-05-28 15:01:39 +01:00
Ginger Bill 80c034ec7c Change naming convention from Ada_Like to RustLike
Naming Conventions:
In general, PascalCase for types and snake_case for values

Import Name:        snake_case (but prefer single word)
Types:              PascalCase
Union Variants:     PascalCase
Enum Values:        PascalCase
Procedures:         snake_case
Local Variables:    snake_case
Constant Variables: SCREAMING_SNAKE_CASE
2017-05-28 14:47:11 +01:00
Ginger Bill b41f09b730 Experimental try for ABI for return values on windows
It's all done by reverse engineering it. I may be wrong...
2017-05-28 14:11:00 +01:00
Ginger Bill 06185e1769 Try a different ABI type for return values on Windows 2017-05-28 01:07:52 +01:00
Ginger Bill f8fa7fe380 Fix bug with too many field values in a structure literal. 2017-05-27 20:57:48 +01:00
Ginger Bill 45dbe8d354 default: to case:; no_alias to #no_alias 2017-05-27 11:47:21 +01:00
Ginger Bill ddb99dd638 Fix interval loop constant bug; Fix ir edge checking; Fix vector arithmetic with scalars 2017-05-22 23:29:09 +01:00
Ginger Bill 41aa4e606b Optional main for DLL; access struct elements by "index" 2017-05-17 21:23:52 +01:00
Ginger Bill e025a828ca Fix issue #66 2017-05-14 10:32:48 +01:00
Ginger Bill 807e17207a Merge branch 'master' of https://github.com/gingerBill/Odin 2017-05-13 16:09:04 +01:00
Ginger Bill 3e18f5f057 Fix Ternary Operator IR bug 2017-05-13 16:08:50 +01:00
gingerBill 9637cc5690 Add #ordered to the "raw" types in raw.odin 2017-05-12 16:04:05 +01:00
Ginger Bill ded99a2cab Fix issue with os.file_size on *nix 2017-05-12 10:29:55 +01:00
Ginger Bill 45eecc0905 Reimplement #ordered again 2017-05-12 10:27:14 +01:00
Ginger Bill 87f1a62ca4 Fix alignment for normal structures to match LLVM 2017-05-10 22:51:35 +01:00
Ginger Bill c6d531df95 Add %% operator (divisor modulo) 2017-05-09 16:21:31 +01:00
Ginger Bill 8677c81da7 Fix ir bug; allow formatting options for arrays & et al. 2017-05-09 12:05:17 +01:00
Ginger Bill 5595daf5a3 Revert demo.odin 2017-05-09 10:01:50 +01:00
Ginger Bill 64b5afd820 Fix issue #63 for block comments not terminating at an EOF 2017-05-09 10:01:10 +01:00
Ginger Bill 7692061eef Add XOR for booleans 2017-05-07 20:52:20 +01:00
Ginger Bill f7f2272c50 Fix fmt_float precision 2017-05-07 11:42:27 +01:00
Ginger Bill 03fbdc3f75 Fix IR printing bug with global unicode identifiers 2017-05-06 23:02:47 +01:00
Ginger Bill ea6a4859ed Merge branch 'master' of https://github.com/gingerBill/Odin 2017-05-06 20:56:18 +01:00
Ginger Bill 615fa82d1f Fix using issue #62 2017-05-06 20:55:09 +01:00
gingerBill b60b310121 Merge pull request #61 from ThisDrunkDane/master
Fix constant casing and add several win32 functions, structure and constants
2017-05-05 21:00:58 +01:00
Mikkel Hjortshoej c7f7e562a0 Add following win32 functions
- ShowCursor
	- GetFileAttributesA
	- FindFirstFileA
	- FindNextFileA
	- FindClose

Add following win32 constants
	- MAX_PATH
	- INVALID_FILE_ATTRIBUTES

Add following win32 structure
	- Find_Data
2017-05-05 20:32:48 +02:00
Mikkel Hjortshoej a317237404 Fix casing on FILE_ATTRIBUTE_DIRECTORY 2017-05-05 20:22:18 +02:00
Ginger Bill 51ea59d76a Fix calculation of vector type sizes 2017-05-04 23:18:54 +01:00
Ginger Bill 789b297f32 Add hidden __tag for union variables. 2017-05-04 20:34:50 +01:00
Ginger Bill 3b25f924cb Remove debug bug 2017-05-03 11:01:17 +01:00
Ginger Bill cc6282a6e3 Fix alignment and size bug of enums; Remove #ordered and make the default #ordered. 2017-05-02 21:16:09 +01:00
Ginger Bill 206a3e093c Remove check on array/slice/dynamic element size 2017-05-02 20:17:53 +01:00
Ginger Bill 19bde275a3 Add files in core 2017-05-01 15:30:16 +01:00
Ginger Bill 634ee450f4 v0.2.1 2017-05-01 15:28:26 +01:00
Ginger Bill 750d7256fc Unary expression for vector (fix) 2017-05-01 15:27:21 +01:00
Ginger Bill fae5df2ed8 Fix IR vector arith conv bug 2017-05-01 15:05:56 +01:00
Ginger Bill 01d9161772 Fix value conversion with enum value on for in. 2017-05-01 10:10:07 +01:00
Ginger Bill aceabb2f2f for in iteration of Enum Type (request from issue #58) 2017-05-01 10:02:25 +01:00
Ginger Bill 04f5fff7fa Improve vector math; Make bprint* return string 2017-05-01 00:38:26 +01:00
Ginger Bill dc5587eae2 Fix statement parsing of unary: & and ^ 2017-04-30 17:20:37 +01:00
Constantine Tarasenkov d05ec5e484 Fix link time error about missing -fPIC flag 2017-04-28 18:08:11 +03:00
76 changed files with 28672 additions and 20566 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016 Ginger Bill. All rights reserved. Copyright (c) 2016-2017 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
+4 -5
View File
@@ -8,7 +8,6 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
* built for modern systems * built for modern systems
* joy of programming * joy of programming
* metaprogramming * metaprogramming
* designed for good programmers
Website: [https://odin.handmade.network/](https://odin.handmade.network/) Website: [https://odin.handmade.network/](https://odin.handmade.network/)
@@ -20,15 +19,15 @@ Website: [https://odin.handmade.network/](https://odin.handmade.network/)
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM) * [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s) * [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78) * [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8) * [when, for & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g) * [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
## Requirements to build and run ## Requirements to build and run
- Windows - Windows
* x86-64 * x86-64
* MSVC 2015 installed (C99 support) * MSVC 2015 installed (C++11 support)
* [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe` * [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
* Requires MSVC's link.exe as the linker * Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path * run `vcvarsall.bat` to setup the path
@@ -42,7 +41,7 @@ Website: [https://odin.handmade.network/](https://odin.handmade.network/)
* x86-64 * x86-64
* Build tools (ld) * Build tools (ld)
* LLVM installed * LLVM installed
* Clang installed (temporary - this is calling the linker for now) * Clang installed (temporary - this is Calling the linker for now)
## Warnings ## Warnings
+5 -8
View File
@@ -4,8 +4,8 @@
set exe_name=odin.exe set exe_name=odin.exe
:: Debug = 0, Release = 1 :: Debug = 0, Release = 1
set release_mode=0 set release_mode=1
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR- set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug if %release_mode% EQU 0 ( rem Debug
set compiler_flags=%compiler_flags% -Od -MDd -Z7 set compiler_flags=%compiler_flags% -Od -MDd -Z7
@@ -38,16 +38,13 @@ if %release_mode% EQU 0 ( rem Debug
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings% set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
set linker_settings=%libs% %linker_flags% set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.c" ^ cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^ /link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin && odin run code/demo.odin -opt=0
rem && odin build code/metagen.odin ^ rem && odin docs core/fmt.odin
rem && call "code\metagen.exe" "src\ast_nodes.metagen"
rem && odin run code/Jaze/src/main.odin
del *.obj > NUL 2> NUL del *.obj > NUL 2> NUL
+3 -3
View File
@@ -2,8 +2,8 @@
release_mode=0 release_mode=0
warnings_to_disable="-std=c11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined" warnings_to_disable="-std=c++11 -g -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
libraries="-pthread -ldl -lm" libraries="-pthread -ldl -lm -lstdc++"
other_args="" other_args=""
compiler="clang" compiler="clang"
@@ -19,6 +19,6 @@ if [[ "$(uname)" == "Darwin" ]]; then
other_args="${other_args} -liconv" other_args="${other_args} -liconv"
fi fi
${compiler} src/main.c ${warnings_to_disable} ${libraries} ${other_args} -o odin ${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
./odin run code/demo.odin ./odin run code/demo.odin
+595 -12
View File
@@ -1,18 +1,601 @@
#import "fmt.odin";
main :: proc() { import (
immutable program := "+ + * - /"; "fmt.odin";
accumulator := 0; "strconv.odin";
"mem.odin";
"thread.odin" when ODIN_OS == "windows";
win32 "sys/windows.odin" when ODIN_OS == "windows";
for token in program { /*
match token { "atomics.odin";
case '+': accumulator += 1; "bits.odin";
case '-': accumulator -= 1; "hash.odin";
case '*': accumulator *= 2; "math.odin";
case '/': accumulator /= 2; "opengl.odin";
default: // Ignore everything else "os.odin";
"raw.odin";
"sort.odin";
"strings.odin";
"sync.odin";
"types.odin";
"utf8.odin";
"utf16.odin";
*/
)
general_stuff :: proc() {
{ // `do` for inline statmes rather than block
foo :: proc() do fmt.println("Foo!");
if false do foo();
for false do foo();
when false do foo();
if false do foo();
else do foo();
}
{ // Removal of `++` and `--` (again)
x: int;
x += 1;
x -= 1;
}
{ // Casting syntaxes
i := i32(137);
ptr := &i;
fp1 := (^f32)(ptr);
// ^f32(ptr) == ^(f32(ptr))
fp2 := cast(^f32)ptr;
f1 := (^f32)(ptr)^;
f2 := (cast(^f32)ptr)^;
// Questions: Should there be two ways to do it?
}
/*
* Remove *_val_of built-in procedures
* size_of, align_of, offset_of
* type_of, type_info_of
*/
{ // `expand_to_tuple` built-in procedure
Foo :: struct {
x: int;
b: bool;
}
f := Foo{137, true};
x, b := expand_to_tuple(f);
fmt.println(f);
fmt.println(x, b);
fmt.println(expand_to_tuple(f));
}
{
// .. half-closed range
// ... open range
for in 0..2 {} // 0, 1
for in 0...2 {} // 0, 1, 2
}
}
nested_struct_declarations :: proc() {
{
FooInteger :: int;
Foo :: struct {
i: FooInteger;
};
f := Foo{FooInteger(137)};
}
{
Foo :: struct {
Integer :: int;
i: Integer;
}
f := Foo{Foo.Integer(137)};
}
}
default_struct_values :: proc() {
{
Vector3 :: struct {
x: f32;
y: f32;
z: f32;
}
v: Vector3;
fmt.println(v);
}
{
// Default values must be constants
Vector3 :: struct {
x: f32 = 1;
y: f32 = 4;
z: f32 = 9;
}
v: Vector3;
fmt.println(v);
v = Vector3{};
fmt.println(v);
// Uses the same semantics as a default values in a procedure
v = Vector3{137};
fmt.println(v);
v = Vector3{z = 137};
fmt.println(v);
}
{
Vector3 :: struct {
x := 1.0;
y := 4.0;
z := 9.0;
}
stack_default: Vector3;
stack_literal := Vector3{};
heap_one := new(Vector3); defer free(heap_one);
heap_two := new_clone(Vector3{}); defer free(heap_two);
fmt.println("stack_default - ", stack_default);
fmt.println("stack_literal - ", stack_literal);
fmt.println("heap_one - ", heap_one^);
fmt.println("heap_two - ", heap_two^);
N :: 4;
stack_array: [N]Vector3;
heap_array := new([N]Vector3); defer free(heap_array);
heap_slice := make([]Vector3, N); defer free(heap_slice);
fmt.println("stack_array[1] - ", stack_array[1]);
fmt.println("heap_array[1] - ", heap_array[1]);
fmt.println("heap_slice[1] - ", heap_slice[1]);
}
}
union_type :: proc() {
{
val: union{int, bool};
val = 137;
if i, ok := val.(int); ok {
fmt.println(i);
}
val = true;
fmt.println(val);
val = nil;
match v in val {
case int: fmt.println("int", v);
case bool: fmt.println("bool", v);
case: fmt.println("nil");
}
}
{
// There is a duality between `any` and `union`
// An `any` has a pointer to the data and allows for any type (open)
// A `union` has as binary blob to store the data and allows only certain types (closed)
// The following code is with `any` but has the same syntax
val: any;
val = 137;
if i, ok := val.(int); ok {
fmt.println(i);
}
val = true;
fmt.println(val);
val = nil;
match v in val {
case int: fmt.println("int", v);
case bool: fmt.println("bool", v);
case: fmt.println("nil");
} }
} }
fmt.printf("The program \"%s\" calculates the value %d\n", program, accumulator); Vector3 :: struct {
x, y, z: f32;
};
Quaternion :: struct {
x, y, z: f32;
w: f32 = 1;
};
// More realistic examples
{
// NOTE(bill): For the above basic examples, you may not have any
// particular use for it. However, my main use for them is not for these
// simple cases. My main use is for hierarchical types. Many prefer
// subtyping, embedding the base data into the derived types. Below is
// an example of this for a basic game Entity.
Entity :: struct {
id: u64;
name: string;
position: Vector3;
orientation: Quaternion;
derived: any;
}
Frog :: struct {
using entity: Entity;
jump_height: f32;
}
Monster :: struct {
using entity: Entity;
is_robot: bool;
is_zombie: bool;
}
// See `parametric_polymorphism` procedure for details
new_entity :: proc(T: type) -> ^Entity {
t := new(T);
t.derived = t^;
return t;
}
entity := new_entity(Monster);
match e in entity.derived {
case Frog:
fmt.println("Ribbit");
case Monster:
if e.is_robot do fmt.println("Robotic");
if e.is_zombie do fmt.println("Grrrr!");
}
}
{
// NOTE(bill): A union can be used to achieve something similar. Instead
// of embedding the base data into the derived types, the derived data
// in embedded into the base type. Below is the same example of the
// basic game Entity but using an union.
Entity :: struct {
id: u64;
name: string;
position: Vector3;
orientation: Quaternion;
derived: union {Frog, Monster};
}
Frog :: struct {
using entity: ^Entity;
jump_height: f32;
}
Monster :: struct {
using entity: ^Entity;
is_robot: bool;
is_zombie: bool;
}
// See `parametric_polymorphism` procedure for details
new_entity :: proc(T: type) -> ^Entity {
t := new(Entity);
t.derived = T{entity = t};
return t;
}
entity := new_entity(Monster);
match e in entity.derived {
case Frog:
fmt.println("Ribbit");
case Monster:
if e.is_robot do fmt.println("Robotic");
if e.is_zombie do fmt.println("Grrrr!");
}
// NOTE(bill): As you can see, the usage code has not changed, only its
// memory layout. Both approaches have their own advantages but they can
// be used together to achieve different results. The subtyping approach
// can allow for a greater control of the memory layout and memory
// allocation, e.g. storing the derivatives together. However, this is
// also its disadvantage. You must either preallocate arrays for each
// derivative separation (which can be easily missed) or preallocate a
// bunch of "raw" memory; determining the maximum size of the derived
// types would require the aid of metaprogramming. Unions solve this
// particular problem as the data is stored with the base data.
// Therefore, it is possible to preallocate, e.g. [100]Entity.
// It should be noted that the union approach can have the same memory
// layout as the any and with the same type restrictions by using a
// pointer type for the derivatives.
/*
Entity :: struct {
...
derived: union{^Frog, ^Monster};
}
Frog :: struct {
using entity: Entity;
...
}
Monster :: struct {
using entity: Entity;
...
}
new_entity :: proc(T: type) -> ^Entity {
t := new(T);
t.derived = t;
return t;
}
*/
}
} }
parametric_polymorphism :: proc() {
print_value :: proc(value: $T) {
fmt.printf("print_value: %T %v\n", value, value);
}
v1: int = 1;
v2: f32 = 2.1;
v3: f64 = 3.14;
v4: string = "message";
print_value(v1);
print_value(v2);
print_value(v3);
print_value(v4);
fmt.println();
add :: proc(p, q: $T) -> T {
x: T = p + q;
return x;
}
a := add(3, 4);
fmt.printf("a: %T = %v\n", a, a);
b := add(3.2, 4.3);
fmt.printf("b: %T = %v\n", b, b);
// This is how `new` is implemented
alloc_type :: proc(T: type) -> ^T {
t := cast(^T)alloc(size_of(T), align_of(T));
t^ = T{}; // Use default initialization value
return t;
}
copy_slice :: proc(dst, src: []$T) -> int {
n := min(len(dst), len(src));
if n > 0 {
mem.copy(&dst[0], &src[0], n*size_of(T));
}
return n;
}
double_params :: proc(a: $A, b: $B) -> A {
return a + A(b);
}
fmt.println(double_params(12, 1.345));
{ // Polymorphic Types and Type Specialization
Table :: struct(Key, Value: type) {
Slot :: struct {
occupied: bool;
hash: u32;
key: Key;
value: Value;
}
SIZE_MIN :: 32;
count: int;
allocator: Allocator;
slots: []Slot;
}
// Only allow types that are specializations of a (polymorphic) slice
make_slice :: proc(T: type/[]$E, len: int) -> T {
return make(T, len);
}
// Only allow types that are specializations of `Table`
allocate :: proc(table: ^$T/Table, capacity: int) {
c := context;
if table.allocator.procedure != nil do c.allocator = table.allocator;
push_context c {
table.slots = make_slice([]T.Slot, max(capacity, T.SIZE_MIN));
}
}
expand :: proc(table: ^$T/Table) {
c := context;
if table.allocator.procedure != nil do c.allocator = table.allocator;
push_context c {
old_slots := table.slots;
cap := max(2*cap(table.slots), T.SIZE_MIN);
allocate(table, cap);
for s in old_slots do if s.occupied {
put(table, s.key, s.value);
}
free(old_slots);
}
}
// Polymorphic determination of a polymorphic struct
// put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
hash := get_hash(key); // Ad-hoc method which would fail in a different scope
index := find_index(table, key, hash);
if index < 0 {
if f64(table.count) >= 0.75*f64(cap(table.slots)) {
expand(table);
}
assert(table.count <= cap(table.slots));
hash := get_hash(key);
index = int(hash % u32(cap(table.slots)));
for table.slots[index].occupied {
if index += 1; index >= cap(table.slots) {
index = 0;
}
}
table.count += 1;
}
slot := &table.slots[index];
slot.occupied = true;
slot.hash = hash;
slot.key = key;
slot.value = value;
}
// find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
hash := get_hash(key);
index := find_index(table, key, hash);
if index < 0 {
return Value{}, false;
}
return table.slots[index].value, true;
}
find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
if cap(table.slots) <= 0 do return -1;
index := int(hash % u32(cap(table.slots)));
for table.slots[index].occupied {
if table.slots[index].hash == hash {
if table.slots[index].key == key {
return index;
}
}
if index += 1; index >= cap(table.slots) {
index = 0;
}
}
return -1;
}
get_hash :: proc(s: string) -> u32 { // fnv32a
h: u32 = 0x811c9dc5;
for i in 0..len(s) {
h = (h ~ u32(s[i])) * 0x01000193;
}
return h;
}
table: Table(string, int);
for i in 0..36 do put(&table, "Hellope", i);
for i in 0..42 do put(&table, "World!", i);
found, _ := find(&table, "Hellope");
fmt.printf("`found` is %v\n", found);
found, _ = find(&table, "World!");
fmt.printf("`found` is %v\n", found);
// I would not personally design a hash table like this in production
// but this is a nice basic example
// A better approach would either use a `u64` or equivalent for the key
// and let the user specify the hashing function or make the user store
// the hashing procedure with the table
}
}
prefix_table := [...]string{
"White",
"Red",
"Green",
"Blue",
"Octarine",
"Black",
};
threading_example :: proc() {
when ODIN_OS == "windows" {
unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
__bounds_check_error_loc(loc, index, len(array));
array[index] = array[len(array)-1];
pop(array);
}
ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
__bounds_check_error_loc(loc, index, len(array));
copy(array[index..], array[index+1..]);
pop(array);
}
worker_proc :: proc(t: ^thread.Thread) -> int {
for iteration in 1...5 {
fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
// win32.sleep(1);
}
return 0;
}
threads := make([]^thread.Thread, 0, len(prefix_table));
defer free(threads);
for i in 0..len(prefix_table) {
if t := thread.create(worker_proc); t != nil {
t.init_context = context;
t.use_init_context = true;
t.user_index = len(threads);
append(&threads, t);
thread.start(t);
}
}
for len(threads) > 0 {
for i := 0; i < len(threads); {
if t := threads[i]; thread.is_done(t) {
fmt.printf("Thread %d is done\n", t.user_index);
thread.destroy(t);
ordered_remove(&threads, i);
} else {
i += 1;
}
}
}
}
}
main :: proc() {
when true {
fmt.println("\n# general_stuff"); general_stuff();
fmt.println("\n# nested_struct_declarations"); nested_struct_declarations();
fmt.println("\n# default_struct_values"); default_struct_values();
fmt.println("\n# union_type"); union_type();
fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
fmt.println("\n# threading_example"); threading_example();
}
}
+430
View File
@@ -0,0 +1,430 @@
import (
"fmt.odin";
"atomics.odin";
"bits.odin";
"decimal.odin";
"hash.odin";
"math.odin";
"mem.odin";
"opengl.odin";
"os.odin";
"raw.odin";
"strconv.odin";
"strings.odin";
"sync.odin";
"sort.odin";
"types.odin";
"utf8.odin";
"utf16.odin";
/*
*/
)
general_stuff :: proc() {
// Complex numbers
a := 3 + 4i;
b: complex64 = 3 + 4i;
c: complex128 = 3 + 4i;
d := complex(2, 3);
e := a / conj(a);
fmt.println("(3+4i)/(3-4i) =", e);
fmt.println(real(e), "+", imag(e), "i");
// C-style variadic procedures
foreign __llvm_core {
// The variadic part allows for extra type checking too which C does not provide
c_printf :: proc(fmt: ^u8, #c_vararg args: ...any) -> i32 #link_name "printf" ---;
}
str := "%d\n\x00";
// c_printf(&str[0], i32(789456123));
Foo :: struct {
x: int;
y: f32;
z: string;
}
foo := Foo{123, 0.513, "A string"};
x, y, z := expand_to_tuple(foo);
fmt.println(x, y, z);
compile_assert(type_of(x) == int);
compile_assert(type_of(y) == f32);
compile_assert(type_of(z) == string);
// By default, all variables are zeroed
// This can be overridden with the "uninitialized value"
// This is similar to `nil` but applied to everything
undef_int: int = ---;
// Context system is now implemented using Implicit Parameter Passing (IPP)
// The previous implementation was Thread Local Storage (TLS)
// IPP has the advantage that it works on systems without TLS and that you can
// link the context to the stack frame and thus look at previous contexts
//
// It does mean that a pointer is implicitly passed procedures with the default
// Odin calling convention (#cc_odin)
// This can be overridden with something like #cc_contextless or #cc_c if performance
// is worried about
}
foreign_blocks :: proc() {
// See sys/windows.odin
}
default_arguments :: proc() {
hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
fmt.println("\nTesting default arguments:");
hello(1, 2);
hello(1);
hello();
}
named_arguments :: proc() {
Colour :: enum {
Red,
Orange,
Yellow,
Green,
Blue,
Octarine,
};
using Colour;
make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) {
fmt.println();
fmt.printf("My name is %v and I like %v. %v\n", name, favourite_colour, catch_phrase);
}
make_character("Frank", "¡Ay, caramba!", Blue, Green);
// As the procedures have more and more parameters, it is very easy
// to get many of the arguments in the wrong order especialy if the
// types are the same
make_character("¡Ay, caramba!", "Frank", Green, Blue);
// Named arguments help to disambiguate this problem
make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
least_favourite_colour = Green, favourite_colour = Blue);
// The named arguments can be specifed in any order.
make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!",
least_favourite_colour = Green, name = "Dennis");
// NOTE: You cannot mix named arguments with normal values
/*
make_character("Dennis",
favourite_colour = Octarine, catch_phrase = "U wot m8!",
least_favourite_colour = Green);
*/
// Named arguments can also aid with default arguments
numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14,
d := "The Best String!", e := false, f := 10.3/3.1, g := false) {
g_str := g ? "true" : "false";
fmt.printf("How many?! %s: %v\n", s, g_str);
}
numerous_things("First");
numerous_things(s = "Second", g = true);
// Default values can be placed anywhere, not just at the end like in other languages
weird :: proc(pre: string, mid: int = 0, post: string) {
fmt.println(pre, mid, post);
}
weird("How many things", 42, "huh?");
weird(pre = "Prefix", post = "Pat");
}
default_return_values :: proc() {
foo :: proc(x: int) -> (first: string = "Hellope", second := "world!") {
match x {
case 0: return;
case 1: return "Goodbye";
case 2: return "Goodbye", "cruel world...";
case 3: return second = "cruel world...", first = "Goodbye";
}
return second = "my old friend.";
}
fmt.printf("%s %s\n", foo(0));
fmt.printf("%s %s\n", foo(1));
fmt.printf("%s %s\n", foo(2));
fmt.printf("%s %s\n", foo(3));
fmt.printf("%s %s\n", foo(4));
fmt.println();
// A more "real" example
Error :: enum {
None,
WhyTheNumberThree,
TenIsTooBig,
};
Entity :: struct {
name: string;
id: u32;
}
some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
match {
case input == 3: return err = Error.WhyTheNumberThree;
case input >= 10: return err = Error.TenIsTooBig;
}
e := new(Entity);
e.id = u32(input);
return result = e;
}
}
call_location :: proc() {
amazing :: proc(n: int, using loc := #caller_location) {
fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
fully_pathed_filename, line, column);
fmt.printf("Normal -> %d\n", n);
fmt.printf("Amazing -> %d\n", n+1);
fmt.println();
}
loc := #location(main);
fmt.println("`main` is located at", loc);
fmt.println("This line is located at", #location());
fmt.println();
amazing(3);
amazing(4, #location(call_location));
// See _preload.odin for the implementations of `assert` and `panic`
}
explicit_parametric_polymorphic_procedures :: proc() {
// This is how `new` is actually implemented, see _preload.odin
alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T));
int_ptr := alloc_type(int);
defer free(int_ptr);
int_ptr^ = 137;
fmt.println(int_ptr, int_ptr^);
// Named arguments work too!
another_ptr := alloc_type(T = f32);
defer free(another_ptr);
add :: proc(T: type, args: ...T) -> T {
res: T;
for arg in args do res += arg;
return res;
}
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
swap :: proc(T: type, a, b: ^T) {
tmp := a^;
a^ = b^;
b^ = tmp;
}
a, b: int = 3, 4;
fmt.println("Pre-swap:", a, b);
swap(int, &a, &b);
fmt.println("Post-swap:", a, b);
a, b = b, a; // Or use this syntax for this silly example case
Vector2 :: struct {x, y: f32;};
{
// A more complicated example using subtyping
// Something like this could be used in a game
Entity :: struct {
using position: Vector2;
flags: u64;
id: u64;
derived: any;
}
Rock :: struct {
using entity: Entity;
heavy: bool;
}
Door :: struct {
using entity: Entity;
open: bool;
}
Monster :: struct {
using entity: Entity;
is_robot: bool;
is_zombie: bool;
}
new_entity :: proc(T: type, x, y: f32) -> ^T {
result := new(T);
result.derived = result^;
result.x = x;
result.y = y;
return result;
}
entities: [dynamic]^Entity;
rock := new_entity(Rock, 3, 5);
// Named arguments work too!
door := new_entity(T = Door, x = 3, y = 6);
// And named arguments can be any order
monster := new_entity(
y = 1,
x = 2,
T = Monster,
);
append(&entities, rock, door, monster);
fmt.println("Subtyping");
for entity in entities {
match e in entity.derived {
case Rock: fmt.println("Rock", e.x, e.y);
case Door: fmt.println("Door", e.x, e.y);
case Monster: fmt.println("Monster", e.x, e.y);
}
}
}
{
Entity :: struct {
using position: Vector2;
flags: u64;
id: u64;
variant: union { Rock, Door, Monster };
}
Rock :: struct {
using entity: ^Entity;
heavy: bool;
}
Door :: struct {
using entity: ^Entity;
open: bool;
}
Monster :: struct {
using entity: ^Entity;
is_robot: bool;
is_zombie: bool;
}
new_entity :: proc(T: type, x, y: f32) -> ^T {
result := new(Entity);
result.variant = T{entity = result};
result.x = x;
result.y = y;
return cast(^T)&result.variant;
}
entities: [dynamic]^Entity;
rock := new_entity(Rock, 3, 5);
// Named arguments work too!
door := new_entity(T = Door, x = 3, y = 6);
// And named arguments can be any order
monster := new_entity(
y = 1,
x = 2,
T = Monster,
);
append(&entities, rock, door, monster);
fmt.println("Union");
for entity in entities {
match e in entity.variant {
case Rock: fmt.println("Rock", e.x, e.y);
case Door: fmt.println("Door", e.x, e.y);
case Monster: fmt.println("Monster", e.x, e.y);
}
}
}
}
implicit_polymorphic_assignment :: proc() {
yep :: proc(p: proc(x: int)) {
p(123);
}
frank :: proc(x: $T) do fmt.println("frank ->", x);
tim :: proc(x, y: $T) do fmt.println("tim ->", x, y);
yep(frank);
// yep(tim);
}
main :: proc() {
/*
foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y);
foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
foo :: proc(x: type) do fmt.println("#3", type_info(x));
f :: foo;
f(y = 3785.1546, x = 123);
f(x = int, y = 897.513);
f(x = f32);
general_stuff();
foreign_blocks();
default_arguments();
named_arguments();
default_return_values();
call_location();
explicit_parametric_polymorphic_procedures();
implicit_polymorphic_assignment();
// Command line argument(s)!
// -opt=0,1,2,3
*/
/*
program := "+ + * - /";
accumulator := 0;
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
*/
}
+78 -78
View File
@@ -1,38 +1,37 @@
#import win32 "sys/windows.odin" when ODIN_OS == "windows"; import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import wgl "sys/wgl.odin" when ODIN_OS == "windows"; import wgl "sys/wgl.odin" when ODIN_OS == "windows";
#import "fmt.odin"; import "fmt.odin";
#import "math.odin"; import "math.odin";
#import "os.odin"; import "os.odin";
#import gl "opengl.odin"; import gl "opengl.odin";
TWO_HEARTS :: '💕'; const TWO_HEARTS = '💕';
win32_perf_count_freq := win32.GetQueryPerformanceFrequency(); var win32_perf_count_freq = win32.get_query_performance_frequency();
time_now :: proc() -> f64 { proc time_now() -> f64 {
assert(win32_perf_count_freq != 0); assert(win32_perf_count_freq != 0);
counter: i64; var counter: i64;
win32.QueryPerformanceCounter(^counter); win32.query_performance_counter(&counter);
result := cast(f64)counter / cast(f64)win32_perf_count_freq; return f64(counter) / f64(win32_perf_count_freq);
return result;
} }
win32_print_last_error :: proc() { proc win32_print_last_error() {
err_code := cast(int)win32.GetLastError(); var err_code = win32.get_last_error();
if err_code != 0 { if err_code != 0 {
fmt.println("GetLastError: %", err_code); fmt.println("get_last_error: ", err_code);
} }
} }
// Yuk! // Yuk!
to_c_string :: proc(s: string) -> []u8 { proc to_c_string(s: string) -> []u8 {
c_str := make([]u8, len(s)+1); var c_str = make([]u8, len(s)+1);
copy(c_str, cast([]byte)s); copy(c_str, []u8(s));
c_str[len(s)] = 0; c_str[len(s)] = 0;
return c_str; return c_str;
} }
Window :: struct { type Window struct {
width, height: int, width, height: int,
wc: win32.WndClassExA, wc: win32.WndClassExA,
dc: win32.Hdc, dc: win32.Hdc,
@@ -41,52 +40,52 @@ Window :: struct {
c_title: []u8, c_title: []u8,
} }
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) { proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) -> (Window, bool) {
using win32; using win32;
w: Window; var w: Window;
w.width, w.height = msg, height; w.width, w.height = msg, height;
class_name := "Win32-Odin-Window\x00"; var class_name = "Win32-Odin-Window\x00";
c_class_name := ^class_name[0]; var c_class_name = &class_name[0];
if title[len(title)-1] != 0 { if title[len(title)-1] != 0 {
w.c_title = to_c_string(title); w.c_title = to_c_string(title);
} else { } else {
w.c_title = cast([]u8)title; w.c_title = []u8(title);
} }
instance := GetModuleHandleA(nil); var instance = get_module_handle_a(nil);
w.wc = WndClassExA{ w.wc = WndClassExA{
size = size_of(WndClassExA), size = size_of(WndClassExA),
style = CS_VREDRAW | CS_HREDRAW, style = CS_VREDRAW | CS_HREDRAW,
instance = cast(Hinstance)instance, instance = Hinstance(instance),
class_name = c_class_name, class_name = c_class_name,
wnd_proc = window_proc, wnd_proc = window_proc,
}; };
if RegisterClassExA(^w.wc) == 0 { if register_class_ex_a(&w.wc) == 0 {
win32_print_last_error(); win32_print_last_error();
return w, false; return w, false;
} }
w.hwnd = CreateWindowExA(0, w.hwnd = create_window_ex_a(0,
c_class_name, ^w.c_title[0], c_class_name, &w.c_title[0],
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
cast(i32)w.width, cast(i32)w.height, i32(w.width), i32(w.height),
nil, nil, instance, nil); nil, nil, instance, nil);
if w.hwnd == nil { if w.hwnd == nil {
win32_print_last_error(); win32_print_last_error();
return w, false; return w, false;
} }
w.dc = GetDC(w.hwnd); w.dc = get_dc(w.hwnd);
{ {
pfd := PIXELFORMATDESCRIPTOR{ var pfd = PixelFormatDescriptor{
size = size_of(PIXELFORMATDESCRIPTOR), size = size_of(PixelFormatDescriptor),
version = 1, version = 1,
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
pixel_type = PFD_TYPE_RGBA, pixel_type = PFD_TYPE_RGBA,
@@ -97,88 +96,89 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc
layer_type = PFD_MAIN_PLANE, layer_type = PFD_MAIN_PLANE,
}; };
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil); set_pixel_format(w.dc, choose_pixel_format(w.dc, &pfd), nil);
w.opengl_context = wgl.CreateContext(w.dc); w.opengl_context = wgl.create_context(w.dc);
wgl.MakeCurrent(w.dc, w.opengl_context); wgl.make_current(w.dc, w.opengl_context);
attribs := [8]i32{ var attribs = [8]i32{
wgl.CONTEXT_MAJOR_VERSION_ARB, 2, wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
wgl.CONTEXT_MINOR_VERSION_ARB, 1, wgl.CONTEXT_MINOR_VERSION_ARB, 1,
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, // NOTE(bill): tells the proc that this is the end of attribs 0, // NOTE(bill): tells the proc that this is the end of attribs
}; };
wgl_str := "wglCreateContextAttribsARB\x00"; var wgl_str = "wglCreateContextAttribsARB\x00";
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.GetProcAddress(^wgl_str[0]); var wglCreateContextAttribsARB = wgl.CreateContextAttribsARBType(wgl.get_proc_address(&wgl_str[0]));
w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]); w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
wgl.MakeCurrent(w.dc, w.rc); wgl.make_current(w.dc, w.rc);
SwapBuffers(w.dc); swap_buffers(w.dc);
} }
return w, true; return w, true;
} }
destroy_window :: proc(w: ^Window) { proc destroy_window(w: ^Window) {
free(w.c_title); free(w.c_title);
} }
display_window :: proc(w: ^Window) { proc display_window(w: ^Window) {
win32.SwapBuffers(w.dc); win32.swap_buffers(w.dc);
} }
run :: proc() { proc run() {
using win32;
using math; using math;
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline { proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
using win32;
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT { if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
os.exit(0); os.exit(0);
return 0; return 0;
} }
return DefWindowProcA(hwnd, msg, wparam, lparam); return def_window_proc_a(hwnd, msg, wparam, lparam);
} }
window, window_success := make_window("Odin Language Demo", 854, 480, cast(Wnd_Proc)win32_proc); var window, window_success = make_window("Odin Language Demo", 854, 480, win32.WndProc(win32_proc));
if !window_success { if !window_success {
return; return;
} }
defer destroy_window(^window); defer destroy_window(&window);
gl.init(); gl.init();
using win32;
prev_time := time_now(); var prev_time = time_now();
running := true; var running = true;
pos := Vec2{100, 100}; var pos = Vec2{100, 100};
for running { for running {
curr_time := time_now(); var curr_time = time_now();
dt := cast(f32)(curr_time - prev_time); var dt = f32(curr_time - prev_time);
prev_time = curr_time; prev_time = curr_time;
msg: Msg; var msg: Msg;
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 { for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
if msg.message == WM_QUIT { if msg.message == WM_QUIT {
running = false; running = false;
} }
TranslateMessage(^msg); translate_message(&msg);
DispatchMessageA(^msg); dispatch_message_a(&msg);
} }
if is_key_down(Key_Code.ESCAPE) { if is_key_down(KeyCode.Escape) {
running = false; running = false;
} }
{ {
SPEED :: 500; const SPEED = 500;
v: Vec2; var v: Vec2;
if is_key_down(Key_Code.RIGHT) { v[0] += 1; } if is_key_down(KeyCode.Right) { v[0] += 1; }
if is_key_down(Key_Code.LEFT) { v[0] -= 1; } if is_key_down(KeyCode.Left) { v[0] -= 1; }
if is_key_down(Key_Code.UP) { v[1] += 1; } if is_key_down(KeyCode.Up) { v[1] += 1; }
if is_key_down(Key_Code.DOWN) { v[1] -= 1; } if is_key_down(KeyCode.Down) { v[1] -= 1; }
v = norm(v); v = norm(v);
@@ -190,10 +190,10 @@ run :: proc() {
gl.Clear(gl.COLOR_BUFFER_BIT); gl.Clear(gl.COLOR_BUFFER_BIT);
gl.LoadIdentity(); gl.LoadIdentity();
gl.Ortho(0, cast(f64)window.width, gl.Ortho(0, f64(window.width),
0, cast(f64)window.height, 0, 1); 0, f64(window.height), 0, 1);
draw_rect :: proc(x, y, w, h: f32) { proc draw_rect(x, y, w, h: f32) {
gl.Begin(gl.TRIANGLES); gl.Begin(gl.TRIANGLES);
defer gl.End(); defer gl.End();
@@ -208,15 +208,15 @@ run :: proc() {
draw_rect(pos.x, pos.y, 50, 50); draw_rect(pos.x, pos.y, 50, 50);
display_window(^window); display_window(&window);
ms_to_sleep := cast(i32)(16 - 1000*dt); var ms_to_sleep = i32(16 - 1000*dt);
if ms_to_sleep > 0 { if ms_to_sleep > 0 {
win32.Sleep(ms_to_sleep); win32.sleep(ms_to_sleep);
} }
} }
} }
main :: proc() { proc main() {
run(); run();
} }
+62 -58
View File
@@ -1,12 +1,12 @@
#import "fmt.odin"; import "fmt.odin";
#foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows"; foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
SOCKET :: #type uint; type SOCKET uint;
INVALID_SOCKET :: ~(cast(SOCKET)0); const INVALID_SOCKET = ~SOCKET(0);
AF :: enum i32 { type AF enum i32 {
UNSPEC = 0, // unspecified UNSPEC = 0, // unspecified
UNIX = 1, // local to host (pipes, portals) UNIX = 1, // local to host (pipes, portals)
INET = 2, // internetwork: UDP, TCP, etc. INET = 2, // internetwork: UDP, TCP, etc.
@@ -37,19 +37,22 @@ AF :: enum i32 {
MAX = 26, MAX = 26,
}; };
SOCK_STREAM :: 1; const (
SOCKET_ERROR :: -1; SOCK_STREAM = 1;
IPPROTO_TCP :: 6; SOCKET_ERROR = -1;
AI_PASSIVE :: 0x0020; IPPROTO_TCP = 6;
SOMAXCONN :: 128; AI_PASSIVE = 0x0020;
SOMAXCONN = 128;
)
const (
SD_RECEIVE = 0;
SD_SEND = 1;
SD_BOTH = 2;
)
SD_RECEIVE :: 0; const WSADESCRIPTION_LEN = 256;
SD_SEND :: 1; const WSASYS_STATUS_LEN = 128;
SD_BOTH :: 2; type WSADATA struct #ordered {
WSADESCRIPTION_LEN :: 256;
WSASYS_STATUS_LEN :: 128;
WSADATA :: struct #ordered {
version: i16, version: i16,
high_version: i16, high_version: i16,
@@ -57,12 +60,12 @@ WSADATA :: struct #ordered {
// NOTE(bill): This is x64 ordering // NOTE(bill): This is x64 ordering
max_sockets: u16, max_sockets: u16,
max_udp_dg: u16, max_udp_dg: u16,
vendor_info: ^byte, vendor_info: ^u8,
description: [WSADESCRIPTION_LEN+1]byte, description: [WSADESCRIPTION_LEN+1]u8,
system_status: [WSASYS_STATUS_LEN+1]byte, system_status: [WSASYS_STATUS_LEN+1]u8,
} }
addrinfo :: struct #ordered { type addrinfo struct #ordered {
flags: i32, flags: i32,
family: i32, family: i32,
socktype: i32, socktype: i32,
@@ -73,52 +76,53 @@ addrinfo :: struct #ordered {
next: ^addrinfo, next: ^addrinfo,
} }
sockaddr :: struct #ordered { type sockaddr struct #ordered {
family: u16, family: u16,
data: [14]byte, data: [14]u8,
} }
foreign ws2 {
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2; proc WSAStartup (version_requested: i16, data: ^WSADATA) -> i32;
WSACleanup :: proc() -> i32 #foreign ws2; proc WSACleanup () -> i32;
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2; proc getaddrinfo (node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32;
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2; proc freeaddrinfo (ai: ^addrinfo);
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2; proc socket (af, type_, protocol: i32) -> SOCKET;
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2; proc closesocket (s: SOCKET) -> i32;
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2; proc bind (s: SOCKET, name: ^sockaddr, name_len: i32) -> i32;
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2; proc listen (s: SOCKET, back_log: i32) -> i32;
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2; proc accept (s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET;
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2; proc recv (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2; proc send (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2; proc shutdown (s: SOCKET, how: i32) -> i32;
WSAGetLastError :: proc() -> i32 #foreign ws2; proc WSAGetLastError() -> i32;
}
to_c_string :: proc(s: string) -> ^byte { proc to_c_string(s: string) -> ^u8 {
c_str := new_slice(byte, s.count+1); var c_str = make([]u8, len(s)+1);
assert(c_str.data != nil); copy(c_str, []u8(s));
copy(c_str, cast([]byte)s); c_str[len(s)] = 0;
c_str[s.count] = 0; return &c_str[0];
return c_str.data;
} }
run :: proc() { proc run() {
wsa: WSADATA; var (
res: ^addrinfo = nil; wsa: WSADATA;
hints: addrinfo; res: ^addrinfo = nil;
s, client: SOCKET; hints: addrinfo;
s, client: SOCKET;
)
if WSAStartup(2 | (2 << 8), ^wsa) != 0 { if WSAStartup(2 | (2 << 8), &wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError()); fmt.println("WSAStartup failed: ", WSAGetLastError());
return; return;
} }
defer WSACleanup(); defer WSACleanup();
hints.family = cast(i32)AF.INET; hints.family = i32(AF.INET);
hints.socktype = SOCK_STREAM; hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP; hints.protocol = IPPROTO_TCP;
hints.flags = AI_PASSIVE; hints.flags = AI_PASSIVE;
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 { if getaddrinfo(nil, to_c_string("8080"), &hints, &res) != 0 {
fmt.println("getaddrinfo failed: ", WSAGetLastError()); fmt.println("getaddrinfo failed: ", WSAGetLastError());
return; return;
} }
@@ -131,7 +135,7 @@ run :: proc() {
} }
defer closesocket(s); defer closesocket(s);
bind(s, res.addr, cast(i32)res.addrlen); bind(s, res.addr, i32(res.addrlen));
listen(s, SOMAXCONN); listen(s, SOMAXCONN);
client = accept(s, nil, 0); client = accept(s, nil, 0);
@@ -141,7 +145,7 @@ run :: proc() {
} }
defer closesocket(client); defer closesocket(client);
html := var html =
`HTTP/1.1 200 OK `HTTP/1.1 200 OK
Connection: close Connection: close
Content-type: text/html Content-type: text/html
@@ -156,12 +160,12 @@ Content-type: text/html
</html> </html>
`; `;
buf: [1024]byte; var buf: [1024]u8;
for { for {
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0); var bytes = recv(client, &buf[0], i32(len(buf)), 0);
if bytes > 0 { if bytes > 0 {
// fmt.println(buf[:bytes] as string) // fmt.println(string(buf[0..<bytes]))
bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0); var bytes_sent = send(client, &html[0], i32(len(html)-1), 0);
if bytes_sent == SOCKET_ERROR { if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError()); fmt.println("send failed: ", WSAGetLastError());
return; return;
+233 -224
View File
@@ -1,35 +1,42 @@
#import win32 "sys/windows.odin"; import (
#import "fmt.odin"; win32 "sys/windows.odin";
#import "os.odin"; "fmt.odin";
#import "mem.odin"; "os.odin";
"mem.odin";
)
CANVAS_WIDTH :: 128; const (
CANVAS_HEIGHT :: 128; CANVAS_WIDTH = 128;
CANVAS_SCALE :: 3; CANVAS_HEIGHT = 128;
FRAME_TIME :: 1.0/30.0; CANVAS_SCALE = 3;
WINDOW_TITLE :: "Punity\x00"; FRAME_TIME = 1.0/30.0;
WINDOW_TITLE = "Punity\x00";
)
_ := compile_assert(CANVAS_WIDTH % 16 == 0); const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE; const (
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE; WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
)
const (
STACK_CAPACITY = 1<<20;
STORAGE_CAPACITY = 1<<20;
STACK_CAPACITY :: 1<<20; DRAW_LIST_RESERVE = 128;
STORAGE_CAPACITY :: 1<<20;
DRAW_LIST_RESERVE :: 128; MAX_KEYS = 256;
)
MAX_KEYS :: 256; type Core struct {
Core :: struct {
stack: ^Bank, stack: ^Bank,
storage: ^Bank, storage: ^Bank,
running: bool, running: bool,
key_modifiers: u32, key_modifiers: u32,
key_states: [MAX_KEYS]byte, key_states: [MAX_KEYS]u8,
key_deltas: [MAX_KEYS]byte, key_deltas: [MAX_KEYS]u8,
perf_frame, perf_frame,
perf_frame_inner, perf_frame_inner,
@@ -45,52 +52,52 @@ Core :: struct {
draw_list: ^Draw_List, draw_list: ^Draw_List,
} }
Perf_Span :: struct { type Perf_Span struct {
stamp: f64, stamp: f64,
delta: f32, delta: f32,
} }
Bank :: struct { type Bank struct {
memory: []byte, memory: []u8,
cursor: int, cursor: int,
} }
Bank_State :: struct { type Bank_State struct {
state: Bank, state: Bank,
bank: ^Bank, bank: ^Bank,
} }
Color :: raw_union { type Color raw_union {
using channels: struct{a, b, g, r: byte}, using channels: struct{a, b, g, r: u8},
rgba: u32, rgba: u32,
} }
Palette :: struct { type Palette struct {
colors: [256]Color, colors: [256]Color,
colors_count: byte, colors_count: u8,
} }
Rect :: raw_union { type Rect raw_union {
using minmax: struct {min_x, min_y, max_x, max_y: int}, using minmax: struct {min_x, min_y, max_x, max_y: int},
using pos: struct {left, top, right, bottom: int}, using pos: struct {left, top, right, bottom: int},
e: [4]int, e: [4]int,
} }
Bitmap :: struct { type Bitmap struct {
pixels: []byte, pixels: []u8,
width: int, width: int,
height: int, height: int,
} }
Font :: struct { type Font struct {
using bitmap: Bitmap, using bitmap: Bitmap,
char_width: int, char_width: int,
char_height: int, char_height: int,
} }
Canvas :: struct { type Canvas struct {
using bitmap: ^Bitmap, using bitmap: ^Bitmap,
palette: Palette, palette: Palette,
translate_x: int, translate_x: int,
@@ -99,89 +106,92 @@ Canvas :: struct {
font: ^Font, font: ^Font,
} }
DrawFlag :: enum { type DrawFlag enum {
NONE = 0, NONE = 0,
FLIP_H = 1<<0, FLIP_H = 1<<0,
FLIP_V = 1<<1, FLIP_V = 1<<1,
MASK = 1<<2, MASK = 1<<2,
} }
Draw_Item :: struct {} type Draw_Item struct {}
Draw_List :: struct { type Draw_List struct {
items: []Draw_Item, items: []Draw_Item,
} }
Key :: enum { type Key enum {
MOD_SHIFT = 0x0001, ModShift = 0x0001,
MOD_CONTROL = 0x0002, ModControl = 0x0002,
MOD_ALT = 0x0004, ModAlt = 0x0004,
MOD_SUPER = 0x0008, ModSuper = 0x0008,
UNKNOWN =-1,
INVALID =-2,
LBUTTON = 1, Unknown =-1,
RBUTTON = 2, Invalid =-2,
CANCEL = 3,
MBUTTON = 4,
BACK = 8,
TAB = 9, Lbutton = 1,
CLEAR = 12, Rbutton = 2,
RETURN = 13, Cancel = 3,
SHIFT = 16, Mbutton = 4,
CONTROL = 17,
MENU = 18,
PAUSE = 19, Back = 8,
CAPITAL = 20, Tab = 9,
KANA = 0x15, Clear = 12,
HANGEUL = 0x15, Return = 13,
HANGUL = 0x15, Shift = 16,
JUNJA = 0x17, Control = 17,
FINAL = 0x18, Menu = 18,
HANJA = 0x19, Pause = 19,
KANJI = 0x19, Capital = 20,
ESCAPE = 0x1B, Kana = 0x15,
CONVERT = 0x1C, Hangeul = 0x15,
NONCONVERT = 0x1D, Hangul = 0x15,
ACCEPT = 0x1E, Junja = 0x17,
MODECHANGE = 0x1F, Final = 0x18,
SPACE = 32, Hanja = 0x19,
PRIOR = 33, Kanji = 0x19,
NEXT = 34, Escape = 0x1B,
END = 35, Convert = 0x1C,
HOME = 36, NonConvert = 0x1D,
LEFT = 37, Accept = 0x1E,
UP = 38, ModeChange = 0x1F,
RIGHT = 39, Space = 32,
DOWN = 40, Prior = 33,
SELECT = 41, Next = 34,
PRINT = 42, End = 35,
EXEC = 43, Home = 36,
SNAPSHOT = 44, Left = 37,
INSERT = 45, Up = 38,
DELETE = 46, Right = 39,
HELP = 47, Down = 40,
LWIN = 0x5B, Select = 41,
RWIN = 0x5C, Print = 42,
APPS = 0x5D, Exec = 43,
SLEEP = 0x5F, Snapshot = 44,
NUMPAD0 = 0x60, Insert = 45,
NUMPAD1 = 0x61, Delete = 46,
NUMPAD2 = 0x62, Help = 47,
NUMPAD3 = 0x63, Lwin = 0x5B,
NUMPAD4 = 0x64, Rwin = 0x5C,
NUMPAD5 = 0x65, Apps = 0x5D,
NUMPAD6 = 0x66, Sleep = 0x5F,
NUMPAD7 = 0x67, Numpad0 = 0x60,
NUMPAD8 = 0x68, Numpad1 = 0x61,
NUMPAD9 = 0x69, Numpad2 = 0x62,
MULTIPLY = 0x6A, Numpad3 = 0x63,
ADD = 0x6B, Numpad4 = 0x64,
SEPARATOR = 0x6C, Numpad5 = 0x65,
SUBTRACT = 0x6D, Numpad6 = 0x66,
DECIMAL = 0x6E, Numpad7 = 0x67,
DIVIDE = 0x6F, Numpad8 = 0x68,
Numpad9 = 0x69,
Multiply = 0x6A,
Add = 0x6B,
Separator = 0x6C,
Subtract = 0x6D,
Decimal = 0x6E,
Divide = 0x6F,
F1 = 0x70, F1 = 0x70,
F2 = 0x71, F2 = 0x71,
F3 = 0x72, F3 = 0x72,
@@ -206,32 +216,33 @@ Key :: enum {
F22 = 0x85, F22 = 0x85,
F23 = 0x86, F23 = 0x86,
F24 = 0x87, F24 = 0x87,
NUMLOCK = 0x90, Numlock = 0x90,
SCROLL = 0x91, Scroll = 0x91,
LSHIFT = 0xA0, Lshift = 0xA0,
RSHIFT = 0xA1, Rshift = 0xA1,
LCONTROL = 0xA2, Lcontrol = 0xA2,
RCONTROL = 0xA3, Rcontrol = 0xA3,
LMENU = 0xA4, Lmenu = 0xA4,
RMENU = 0xA5, Rmenu = 0xA5,
APOSTROPHE = 39, /* ' */
COMMA = 44, /* , */ Apostrophe = 39, /* ' */
MINUS = 45, /* - */ Comma = 44, /* , */
PERIOD = 46, /* . */ Minus = 45, /* - */
SLASH = 47, /* / */ Period = 46, /* . */
NUM0 = 48, Slash = 47, /* / */
NUM1 = 49, Num0 = 48,
NUM2 = 50, Num1 = 49,
NUM3 = 51, Num2 = 50,
NUM4 = 52, Num3 = 51,
NUM5 = 53, Num4 = 52,
NUM6 = 54, Num5 = 53,
NUM7 = 55, Num6 = 54,
NUM8 = 56, Num7 = 55,
NUM9 = 57, Num8 = 56,
SEMICOLON = 59, /* ; */ Num9 = 57,
EQUAL = 61, /* = */ Semicolon = 59, /* ; */
Equal = 61, /* = */
A = 65, A = 65,
B = 66, B = 66,
C = 67, C = 67,
@@ -258,56 +269,55 @@ Key :: enum {
X = 88, X = 88,
Y = 89, Y = 89,
Z = 90, Z = 90,
LEFT_BRACKET = 91, /* [ */ LeftBracket = 91, /* [ */
BACKSLASH = 92, /* \ */ Backslash = 92, /* \ */
RIGHT_BRACKET = 93, /* ] */ RightBracket = 93, /* ] */
GRAVE_ACCENT = 96, /* ` */ GraveAccent = 96, /* ` */
}; };
key_down :: proc(k: Key) -> bool { proc key_down(k: Key) -> bool {
return _core.key_states[k] != 0; return _core.key_states[k] != 0;
} }
key_pressed :: proc(k: Key) -> bool { proc key_pressed(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k); return (_core.key_deltas[k] != 0) && key_down(k);
} }
win32_perf_count_freq := win32.GetQueryPerformanceFrequency(); let win32_perf_count_freq = win32.get_query_performance_frequency();
time_now :: proc() -> f64 { proc time_now() -> f64 {
assert(win32_perf_count_freq != 0); assert(win32_perf_count_freq != 0);
counter: i64; var counter: i64;
win32.QueryPerformanceCounter(^counter); win32.query_performance_counter(&counter);
result := cast(f64)counter / cast(f64)win32_perf_count_freq; return f64(counter) / f64(win32_perf_count_freq);
return result;
} }
_core: Core; var _core: Core;
run :: proc(user_init, user_step: proc(c: ^Core)) { proc run(user_init, user_step: proc(c: ^Core)) {
using win32; using win32;
_core.running = true; _core.running = true;
win32_proc :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline #cc_c { proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
win32_app_key_mods :: proc() -> u32 { proc win32_app_key_mods() -> u32 {
mods: u32 = 0; var mods: u32 = 0;
if is_key_down(Key_Code.SHIFT) { if is_key_down(KeyCode.Shift) {
mods |= cast(u32)Key.MOD_SHIFT; mods |= u32(Key.ModShift);
} }
if is_key_down(Key_Code.CONTROL) { if is_key_down(KeyCode.Control) {
mods |= cast(u32)Key.MOD_CONTROL; mods |= u32(Key.ModControl);
} }
if is_key_down(Key_Code.MENU) { if is_key_down(KeyCode.Menu) {
mods |= cast(u32)Key.MOD_ALT; mods |= u32(Key.ModAlt);
} }
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) { if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
mods |= cast(u32)Key.MOD_SUPER; mods |= u32(Key.ModSuper);
} }
return mods; return mods;
@@ -331,61 +341,62 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
return 0; return 0;
case WM_CLOSE: case WM_CLOSE:
PostQuitMessage(0); post_quit_message(0);
_core.running = false; _core.running = false;
return 0; return 0;
} }
return DefWindowProcA(hwnd, msg, wparam, lparam); return def_window_proc_a(hwnd, msg, wparam, lparam);
} }
window_class := WNDCLASSEXA{ var class_name = "Punity\x00";
class_name = (cast(string)"Punity\x00").data, // C-style string var window_class = WndClassExA{
size = size_of(WNDCLASSEXA), class_name = &class_name[0],
size = size_of(WndClassExA),
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC, style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
instance = cast(HINSTANCE)GetModuleHandleA(nil), instance = Hinstance(get_module_handle_a(nil)),
wnd_proc = win32_proc, wnd_proc = win32_proc,
// wnd_proc = DefWindowProcA, // wnd_proc = DefWindowProcA,
background = cast(HBRUSH)GetStockObject(BLACK_BRUSH), background = Hbrush(get_stock_object(BLACK_BRUSH)),
}; };
if RegisterClassExA(^window_class) == 0 { if register_class_ex_a(&window_class) == 0 {
fmt.fprintln(os.stderr, "RegisterClassExA failed"); fmt.fprintln(os.stderr, "register_class_ex_a failed");
return; return;
} }
screen_width := GetSystemMetrics(SM_CXSCREEN); var screen_width = get_system_metrics(SM_CXSCREEN);
screen_height := GetSystemMetrics(SM_CYSCREEN); var screen_height = get_system_metrics(SM_CYSCREEN);
rc: RECT; var rc: Rect;
rc.left = (screen_width - WINDOW_WIDTH) / 2; rc.left = (screen_width - WINDOW_WIDTH) / 2;
rc.top = (screen_height - WINDOW_HEIGHT) / 2; rc.top = (screen_height - WINDOW_HEIGHT) / 2;
rc.right = rc.left + WINDOW_WIDTH; rc.right = rc.left + WINDOW_WIDTH;
rc.bottom = rc.top + WINDOW_HEIGHT; rc.bottom = rc.top + WINDOW_HEIGHT;
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; var style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
assert(AdjustWindowRect(^rc, style, 0) != 0); assert(adjust_window_rect(&rc, style, 0) != 0);
wt := WINDOW_TITLE; var wt = WINDOW_TITLE;
win32_window := CreateWindowExA(0, var win32_window = create_window_ex_a(0,
window_class.class_name, window_class.class_name,
wt.data, &wt[0],
style, style,
rc.left, rc.top, rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top, rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance, nil, nil, window_class.instance,
nil); nil);
if win32_window == nil { if win32_window == nil {
fmt.fprintln(os.stderr, "CreateWindowExA failed"); fmt.fprintln(os.stderr, "create_window_ex_a failed");
return; return;
} }
window_bmi: BITMAPINFO; var window_bmi: BitmapInfo;
window_bmi.size = size_of(BITMAPINFOHEADER); window_bmi.size = size_of(BitmapInfoHeader);
window_bmi.width = CANVAS_WIDTH; window_bmi.width = CANVAS_WIDTH;
window_bmi.height = CANVAS_HEIGHT; window_bmi.height = CANVAS_HEIGHT;
window_bmi.planes = 1; window_bmi.planes = 1;
@@ -393,27 +404,27 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
window_bmi.compression = BI_RGB; window_bmi.compression = BI_RGB;
user_init(^_core); user_init(&_core);
ShowWindow(win32_window, SW_SHOW); show_window(win32_window, SW_SHOW);
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT); var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
defer free(window_buffer); defer free(window_buffer);
for _, i in window_buffer {
for i := 0; i < window_buffer.count; i += 1 {
window_buffer[i] = 0xff00ff; window_buffer[i] = 0xff00ff;
} }
var (
dt: f64;
prev_time = time_now();
curr_time = time_now();
total_time : f64 = 0;
offset_x = 0;
offset_y = 0;
)
dt: f64; var message: Msg;
prev_time := time_now();
curr_time := time_now();
total_time : f64 = 0;
offset_x := 0;
offset_y := 0;
message: MSG;
for _core.running { for _core.running {
curr_time = time_now(); curr_time = time_now();
dt = curr_time - prev_time; dt = curr_time - prev_time;
@@ -424,64 +435,62 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
offset_y += 2; offset_y += 2;
{ {
data: [128]byte; var buf: [128]u8;
buf: fmt.Buffer; var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
buf.data = data[:]; win32.set_window_text_a(win32_window, &s[0]);
fmt.bprintf(^buf, "Punity: %.4f ms\x00", dt*1000);
win32.SetWindowTextA(win32_window, ^buf[0]);
} }
for y := 0; y < CANVAS_HEIGHT; y += 1 { for var y = 0; y < CANVAS_HEIGHT; y++ {
for x := 0; x < CANVAS_WIDTH; x += 1 { for var x = 0; x < CANVAS_WIDTH; x++ {
g := (x % 32) * 8; var g = (x % 32) * 8;
b := (y % 32) * 8; var b = (y % 32) * 8;
window_buffer[x + y*CANVAS_WIDTH] = cast(u32)(g << 8 | b); window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
} }
} }
mem.zero(^_core.key_deltas[0], size_of_val(_core.key_deltas)); mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 { for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
if message.message == WM_QUIT { if message.message == WM_QUIT {
_core.running = false; _core.running = false;
} }
TranslateMessage(^message); translate_message(&message);
DispatchMessageA(^message); dispatch_message_a(&message);
} }
user_step(^_core); user_step(&_core);
dc := GetDC(win32_window); var dc = get_dc(win32_window);
StretchDIBits(dc, stretch_dibits(dc,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE, 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
window_buffer.data, &window_buffer[0],
^window_bmi, &window_bmi,
DIB_RGB_COLORS, DIB_RGB_COLORS,
SRCCOPY); SRCCOPY);
ReleaseDC(win32_window, dc); release_dc(win32_window, dc);
{ {
delta := time_now() - prev_time; var delta = time_now() - prev_time;
ms := cast(i32)((FRAME_TIME - delta) * 1000); var ms = i32((FRAME_TIME - delta) * 1000);
if ms > 0 { if ms > 0 {
win32.Sleep(ms); win32.sleep(ms);
} }
} }
_core.frame += 1; _core.frame++;
} }
} }
main :: proc() { proc main() {
user_init :: proc(c: ^Core) { proc user_init(c: ^Core) {
} }
user_step :: proc(c: ^Core) { proc user_step(c: ^Core) {
} }
-5
View File
@@ -1,5 +0,0 @@
#import "fmt.odin" as fmt
thing :: proc() {
fmt.println("Sub Hello!")
}
-35
View File
@@ -1,35 +0,0 @@
/*#import "fmt.odin"
thing :: proc() {
fmt.println("Hello1!")
}*/
#import "fmt.odin";
main :: proc() {
fmt.println("hello, world!");
}
/*#import "fmt.odin" as .
thing :: proc() {
println("Hello3!")
}
*/
/*#import "fmt.odin" as _
thing :: proc() {
// println("Hello4!")
}
*/
/*
#include "fmt.odin"
thing :: proc() {
println("Hello5!")
}*/
+646 -366
View File
File diff suppressed because it is too large Load Diff
+210 -142
View File
@@ -1,158 +1,226 @@
#shared_global_scope; #shared_global_scope;
__multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
// import "fmt.odin"; bits_in_dword_2 :: size_of(i64) * 4;
lower_mask :: u128(~u64(0) >> bits_in_dword_2);
// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" {
// var _, r := __u128_quo_mod(a, b)
// return r
// }
// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" {
// var n, _ := __u128_quo_mod(a, b)
// return n
// }
// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" {
// var _, r := __i128_quo_mod(a, b)
// return r
// }
// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" {
// var n, _ := __i128_quo_mod(a, b)
// return n
// }
// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
// var s := b >> 127
// b = (b ~ s) - s
// s = a >> 127
// a = (a ~ s) - s
// var n, r := __u128_quo_mod(a as u128, b as u128)
// return (n as i128 ~ s) - s, (r as i128 ~ s) - s
// }
// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" { TWords :: struct #raw_union {
// proc clz(x: u64) -> u64 { all: u128;
// proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64" using _: struct {
// return clz_u64(x, false) when ODIN_ENDIAN == "big" {
// } lo, hi: u64;
// proc ctz(x: u64) -> u64 { } else {
// proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64" hi, lo: u64;
// return ctz_u64(x, false) }
// } };
};
r: TWords;
t: u64;
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask);
t += u64(a >> bits_in_dword_2) * u64(b & lower_mask);
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi = t >> bits_in_dword_2;
t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask);
t += u64(b >> bits_in_dword_2) * u64(a & lower_mask);
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi += t >> bits_in_dword_2;
r.hi += u64(a >> bits_in_dword_2) * u64(b >> bits_in_dword_2);
return r.all;
}
__u128_mod :: proc(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
r: u128;
__u128_quo_mod(a, b, &r);
return r;
}
__u128_quo :: proc(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
return __u128_quo_mod(a, b, nil);
}
__i128_mod :: proc(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
r: i128;
__i128_quo_mod(a, b, &r);
return r;
}
__i128_quo :: proc(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
return __i128_quo_mod(a, b, nil);
}
__i128_quo_mod :: proc(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
s: i128;
s = b >> 127;
b = (b~s) - s;
s = a >> 127;
b = (a~s) - s;
uquo: u128;
urem := __u128_quo_mod(transmute(u128)a, transmute(u128)b, &uquo);
iquo := transmute(i128)uquo;
irem := transmute(i128)urem;
iquo = (iquo~s) - s;
irem = (irem~s) - s;
if rem != nil do rem^ = irem;
return iquo;
}
// u128_lo_hi :: raw_union { __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
// all: u128 alo, ahi := u64(a), u64(a>>64);
// using _lohi: struct {lo, hi: u64;} blo, bhi := u64(b), u64(b>>64);
// } if b == 0 {
if rem != nil do rem^ = 0;
return u128(alo/blo);
}
// n, d, q, r: u128_lo_hi r, d, x, q: u128 = a, b, 1, 0;
// sr: u64
// n.all = a for r >= d && (d>>127)&1 == 0 {
// d.all = b x <<= 1;
d <<= 1;
}
// if n.hi == 0 { for x != 0 {
// if d.hi == 0 { if r >= d {
// return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128 r -= d;
// } q |= x;
// return 0, n.lo as u128 }
// } x >>= 1;
// if d.lo == 0 { d >>= 1;
// if d.hi == 0 { }
// return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
// }
// if n.lo == 0 {
// r.hi = n.hi % d.hi
// r.lo = 0
// return (n.hi / d.hi) as u128, r.all
// }
// if (d.hi & (d.hi-1)) == 0 {
// r.lo = n.lo
// r.hi = n.hi & (d.hi-1)
// return (n.hi >> ctz(d.hi)) as u128, r.all
// }
// sr = clz(d.hi) - clz(n.hi) if rem != nil do rem^ = r;
// if sr > 64 - 2 { return q;
// return 0, n.all }
// }
// sr++
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// if d.hi == 0 {
// if (d.lo & (d.lo - 1)) == 0 {
// var rem := (n.lo % (d.lo - 1)) as u128
// if d.lo == 1 {
// return n.all, rem
// }
// sr = ctz(d.lo)
// q.hi = n.hi >> sr
// q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// return q.all, rem
// }
// sr = 1 + 64 + clz(d.lo) - clz(n.hi) /*
__f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
when true {
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
FP32 :: struct #raw_union {u: u32, f: f32};
// q.all = n.all << (128-sr) magic, was_infnan: FP32;
// r.all = n.all >> sr magic.u = (254-15) << 23;
// if sr == 64 { was_infnan.u = (127+16) << 23;
// q.lo = 0
// q.hi = n.lo
// r.hi = 0
// r.lo = n.hi
// } else if sr < 64 {
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// q.lo = n.lo << (128-sr)
// q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
// r.hi = 0
// r.lo = n.hi >> (sr-64)
// }
// } else {
// sr = clz(d.hi) - clz(n.hi)
// if sr > 64-1 {
// return 0, n.all
// }
// sr++
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.all = n.all >> sr
// if sr < 64 {
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// r.hi = 0
// r.lo = n.hi
// }
// }
// }
// carry: u64 hu := transmute(u16, f);
// for ; sr > 0; sr-- {
// r.hi = (r.hi << 1) | (r.lo >> (64-1))
// r.lo = (r.lo << 1) | (r.hi >> (64-1))
// q.hi = (q.hi << 1) | (q.lo >> (64-1))
// q.lo = (q.lo << 1) | carry
// carry = 0 o := FP32{};
// if r.all >= d.all {
// r.all -= d.all
// carry = 1
// }
// }
// q.all = (q.all << 1) | (carry as u128) o.u = u32(hu & 0x7fff) << 13);
// return q.all, r.all o.f *= magic.f;
// } if o.f >= was_infnan.f {
o.u |= 255 << 23;
}
o.u |= u32(hu & 0x8000) << 16;
return o.f;
} else {
return 0;
}
}
__f32_to_f16 :: proc(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
when false {
// Source: https://gist.github.com/rygorous/2156668
FP16 :: struct #raw_union {u: u16, f: f16};
FP32 :: struct #raw_union {u: u32, f: f32};
f32infty, f16infty, magic: FP32;
f32infty.u = 255<<23;
f16infty.u = 31<<23;
magic.u = 15<<23;
sign_mask :: u32(0x80000000);
round_mask :: ~u32(0x0fff);
f := transmute(FP32, f_);
o: FP16;
sign := f.u & sign_mask;
f.u ~= sign;
// NOTE all the integer compares in this function can be safely
// compiled into signed compares since all operands are below
// 0x80000000. Important if you want fast straight SSE2 code
// (since there's no unsigned PCMPGTD).
if f.u >= f32infty.u { // Inf or NaN (all exponent bits set)
o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
} else { // (De)normalized number or zero
f.u &= round_mask;
f.f *= magic.f;
f.u -= round_mask;
if f.u > f16infty.u {
f.u = f16infty.u; // Clamp to signed infinity if overflowed
}
o.u = u16(f.u >> 13); // Take the bits!
}
o.u |= u16(sign >> 16);
return o.f;
} else {
f := transmute(u32, f_);
h: u16;
hs, he, hf: u16;
fs := (f >> 31) & 1;
fe := (f >> 23) & 0b1111_1111;
ff := (f >> 0) & 0b0111_1111_1111_1111_1111_1111;
add_one := false;
if (fe == 0) {
he = 0;
} else if (fe == 255) {
he = 31;
hf = ff != 0 ? 0x200 : 0;
} else {
ne := fe - 127 + 15;
if ne >= 31 {
he = 31;
} else if ne <= 0 {
if (14-ne) <= 24 {
mant := ff | 0x800000;
hf = u16(mant >> (14-ne));
if (mant >> (13-ne)) & 1 != 0 {
add_one = true;
}
}
} else {
he = u16(ne);
hf = u16(ff >> 13);
if ff&0x1000 != 0 {
add_one = true;
}
}
}
hs = u16(hs);
h |= (he&0b0001_1111)<<10;
h |= (hf&0b0011_1111_1111);
if add_one {
h++;
}
h |= (hs&1) << 15;
return transmute(f16, h);
}
}
__f64_to_f16 :: proc(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
return __f32_to_f16(f32(f));
}
__f16_to_f64 :: proc(f: f16) -> f64 #cc_c #no_inline {
return f64(__f16_to_f32(f));
}
*/
+100
View File
@@ -0,0 +1,100 @@
// TODO(bill): Use assembly instead here to implement atomics
// Inline vs external file?
import win32 "sys/windows.odin" when ODIN_OS == "windows";
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.read_write_barrier(); }
sfence :: proc() { win32.write_barrier(); }
lfence :: proc() { win32.read_barrier(); }
load :: proc(a: ^i32) -> i32 {
return a^;
}
store :: proc(a: ^i32, value: i32) {
a^ = value;
}
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
return win32.interlocked_compare_exchange(a, desired, expected);
}
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
return win32.interlocked_exchange(a, desired);
}
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_exchange_add(a, operand);
}
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_and(a, operand);
}
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_or(a, operand);
}
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock :: proc(a: ^i32) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
load :: proc(a: ^i64) -> i64 {
return a^;
}
store :: proc(a: ^i64, value: i64) {
a^ = value;
}
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
return win32.interlocked_compare_exchange64(a, desired, expected);
}
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
return win32.interlocked_exchange64(a, desired);
}
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_exchange_add64(a, operand);
}
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_and64(a, operand);
}
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_or64(a, operand);
}
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock :: proc(a: ^i64) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
+285
View File
@@ -0,0 +1,285 @@
U8_MIN :: u8(0);
U16_MIN :: u16(0);
U32_MIN :: u32(0);
U64_MIN :: u64(0);
U128_MIN :: u128(0);
I8_MIN :: i8(-0x80);
I16_MIN :: i16(-0x8000);
I32_MIN :: i32(-0x8000_0000);
I64_MIN :: i64(-0x8000_0000_0000_0000);
I128_MIN :: i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
U8_MAX :: ~u8(0);
U16_MAX :: ~u16(0);
U32_MAX :: ~u32(0);
U64_MAX :: ~u64(0);
U128_MAX :: ~u128(0);
I8_MAX :: i8(0x7f);
I16_MAX :: i16(0x7fff);
I32_MAX :: i32(0x7fff_ffff);
I64_MAX :: i64(0x7fff_ffff_ffff_ffff);
I128_MAX :: i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
count_ones :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctpop :: proc(u8) -> u8 #link_name "llvm.ctpop.i8" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctpop :: proc(i8) -> i8 #link_name "llvm.ctpop.i8" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctpop :: proc(u16) -> u16 #link_name "llvm.ctpop.i16" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctpop :: proc(i16) -> i16 #link_name "llvm.ctpop.i16" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctpop :: proc(u32) -> u32 #link_name "llvm.ctpop.i32" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctpop :: proc(i32) -> i32 #link_name "llvm.ctpop.i32" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctpop :: proc(u64) -> u64 #link_name "llvm.ctpop.i64" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctpop :: proc(i64) -> i64 #link_name "llvm.ctpop.i64" ---; return __llvm_ctpop(i); }
count_ones :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctpop :: proc(u128) -> u128 #link_name "llvm.ctpop.i128" ---;return __llvm_ctpop(i); }
count_ones :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctpop :: proc(i128) -> i128 #link_name "llvm.ctpop.i128" ---;return __llvm_ctpop(i); }
count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
count_ones :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
count_zeros :: proc(i: u8) -> u8 { return 8 - count_ones(i); }
count_zeros :: proc(i: i8) -> i8 { return 8 - count_ones(i); }
count_zeros :: proc(i: u16) -> u16 { return 16 - count_ones(i); }
count_zeros :: proc(i: i16) -> i16 { return 16 - count_ones(i); }
count_zeros :: proc(i: u32) -> u32 { return 32 - count_ones(i); }
count_zeros :: proc(i: i32) -> i32 { return 32 - count_ones(i); }
count_zeros :: proc(i: u64) -> u64 { return 64 - count_ones(i); }
count_zeros :: proc(i: i64) -> i64 { return 64 - count_ones(i); }
count_zeros :: proc(i: u128) -> u128 { return 128 - count_ones(i); }
count_zeros :: proc(i: i128) -> i128 { return 128 - count_ones(i); }
count_zeros :: proc(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
count_zeros :: proc(i: int) -> int { return 8*size_of(int) - count_ones(i); }
rotate_left :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
rotate_left :: proc(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
rotate_left :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
rotate_left :: proc(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
rotate_left :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
rotate_left :: proc(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
rotate_left :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
rotate_left :: proc(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
rotate_left :: proc(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
rotate_left :: proc(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
rotate_left :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
rotate_left :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_left(i32(i), s)); } else { return int(rotate_left(i64(i), s)); } }
rotate_right :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
rotate_right :: proc(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
rotate_right :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
rotate_right :: proc(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
rotate_right :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
rotate_right :: proc(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
rotate_right :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
rotate_right :: proc(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
rotate_right :: proc(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
rotate_right :: proc(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
rotate_right :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
rotate_right :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
leading_zeros :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctlz :: proc(u8, bool) -> u8 #link_name "llvm.ctlz.i8" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctlz :: proc(i8, bool) -> i8 #link_name "llvm.ctlz.i8" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctlz :: proc(u16, bool) -> u16 #link_name "llvm.ctlz.i16" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctlz :: proc(i16, bool) -> i16 #link_name "llvm.ctlz.i16" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctlz :: proc(u32, bool) -> u32 #link_name "llvm.ctlz.i32" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctlz :: proc(i32, bool) -> i32 #link_name "llvm.ctlz.i32" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctlz :: proc(u64, bool) -> u64 #link_name "llvm.ctlz.i64" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctlz :: proc(i64, bool) -> i64 #link_name "llvm.ctlz.i64" ---; return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctlz :: proc(u128, bool) -> u128 #link_name "llvm.ctlz.i128" ---;return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctlz :: proc(i128, bool) -> i128 #link_name "llvm.ctlz.i128" ---;return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
leading_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
trailing_zeros :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_cttz :: proc(u8, bool) -> u8 #link_name "llvm.cttz.i8" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_cttz :: proc(i8, bool) -> i8 #link_name "llvm.cttz.i8" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_cttz :: proc(u16, bool) -> u16 #link_name "llvm.cttz.i16" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_cttz :: proc(i16, bool) -> i16 #link_name "llvm.cttz.i16" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_cttz :: proc(u32, bool) -> u32 #link_name "llvm.cttz.i32" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_cttz :: proc(i32, bool) -> i32 #link_name "llvm.cttz.i32" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_cttz :: proc(u64, bool) -> u64 #link_name "llvm.cttz.i64" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_cttz :: proc(i64, bool) -> i64 #link_name "llvm.cttz.i64" ---; return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_cttz :: proc(u128, bool) -> u128 #link_name "llvm.cttz.i128" ---;return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_cttz :: proc(i128, bool) -> i128 #link_name "llvm.cttz.i128" ---;return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
trailing_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
reverse_bits :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_bitreverse :: proc(u8) -> u8 #link_name "llvm.bitreverse.i8" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_bitreverse :: proc(i8) -> i8 #link_name "llvm.bitreverse.i8" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_bitreverse :: proc(u16) -> u16 #link_name "llvm.bitreverse.i16" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_bitreverse :: proc(i16) -> i16 #link_name "llvm.bitreverse.i16" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_bitreverse :: proc(u32) -> u32 #link_name "llvm.bitreverse.i32" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_bitreverse :: proc(i32) -> i32 #link_name "llvm.bitreverse.i32" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_bitreverse :: proc(u64) -> u64 #link_name "llvm.bitreverse.i64" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_bitreverse :: proc(i64) -> i64 #link_name "llvm.bitreverse.i64" ---; return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_bitreverse :: proc(u128) -> u128 #link_name "llvm.bitreverse.i128" ---;return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_bitreverse :: proc(i128) -> i128 #link_name "llvm.bitreverse.i128" ---;return __llvm_bitreverse(i); }
reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
reverse_bits :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
foreign __llvm_core {
byte_swap :: proc(u16) -> u16 #link_name "llvm.bswap.i16" ---;
byte_swap :: proc(i16) -> i16 #link_name "llvm.bswap.i16" ---;
byte_swap :: proc(u32) -> u32 #link_name "llvm.bswap.i32" ---;
byte_swap :: proc(i32) -> i32 #link_name "llvm.bswap.i32" ---;
byte_swap :: proc(u64) -> u64 #link_name "llvm.bswap.i64" ---;
byte_swap :: proc(i64) -> i64 #link_name "llvm.bswap.i64" ---;
byte_swap :: proc(u128) -> u128 #link_name "llvm.bswap.i128" ---;
byte_swap :: proc(i128) -> i128 #link_name "llvm.bswap.i128" ---;
}
byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
byte_swap :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
from_be :: proc(i: u8) -> u8 { return i; }
from_be :: proc(i: i8) -> i8 { return i; }
from_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u8) -> u8 { return i; }
from_le :: proc(i: i8) -> i8 { return i; }
from_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u8) -> u8 { return i; }
to_be :: proc(i: i8) -> i8 { return i; }
to_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u8) -> u8 { return i; }
to_le :: proc(i: i8) -> i8 { return i; }
to_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
overflowing_add :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.uadd.with.overflow.i8" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.sadd.with.overflow.i8" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.uadd.with.overflow.i16" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.sadd.with.overflow.i16" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.uadd.with.overflow.i32" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.sadd.with.overflow.i32" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.uadd.with.overflow.i64" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.sadd.with.overflow.i64" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.uadd.with.overflow.i128" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.sadd.with.overflow.i128" ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_add(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_add(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_add :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_add(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_add(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_sub :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.usub.with.overflow.i8" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.ssub.with.overflow.i8" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.usub.with.overflow.i16" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.ssub.with.overflow.i16" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.usub.with.overflow.i32" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.ssub.with.overflow.i32" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.usub.with.overflow.i64" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.ssub.with.overflow.i64" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.usub.with.overflow.i128" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.ssub.with.overflow.i128" ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_sub(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_sub(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_sub :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_sub(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_sub(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_mul :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.umul.with.overflow.i8" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.smul.with.overflow.i8" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.umul.with.overflow.i16" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.smul.with.overflow.i16" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.umul.with.overflow.i32" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.smul.with.overflow.i32" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.umul.with.overflow.i64" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.smul.with.overflow.i64" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.umul.with.overflow.i128" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.smul.with.overflow.i128" ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_mul(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_mul(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_mul :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_mul(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_mul(i64(lhs), i64(rhs));
return int(x), ok;
}
}
is_power_of_two :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
+41
View File
@@ -0,0 +1,41 @@
CHAR_BIT :: 8;
c_bool :: bool;
c_char :: u8;
c_schar :: i8;
c_uchar :: i8;
c_short :: i16;
c_ushort :: i16;
c_int :: i32;
c_uint :: u32;
c_long :: ODIN_OS == "windows" ?
i32 :
(size_of(int) == 4) ?
i32 :
i64;
c_ulong :: ODIN_OS == "windows" ?
u32 :
(size_of(int) == 4) ?
u32 :
u64;
c_longlong :: i64;
c_ulonglong :: u64;
c_float :: f32;
c_double :: f64;
c_complex_float :: complex64;
c_complex_double :: complex128;
c_size_t :: uint;
c_ssize_t :: int;
c_ptrdiff_t :: int;
c_uintptr_t :: uint;
c_intptr_t :: int;
+49 -51
View File
@@ -3,17 +3,15 @@
// NOTE: This is only for floating point printing and nothing else // NOTE: This is only for floating point printing and nothing else
Decimal :: struct { Decimal :: struct {
digits: [384]byte, // big-endian digits digits: [384]u8; // big-endian digits
count: int, count: int;
decimal_point: int, decimal_point: int;
neg, trunc: bool, neg, trunc: bool;
} }
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string { decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
digit_zero :: proc(buf: []byte) -> int { digit_zero :: proc(buf: []u8) -> int {
for _, i in buf { for _, i in buf do buf[i] = '0';
buf[i] = '0';
}
return len(buf); return len(buf);
} }
@@ -22,35 +20,35 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
// TODO(bill): make this work with a buffer that's not big enough // TODO(bill): make this work with a buffer that's not big enough
assert(len(buf) >= n); assert(len(buf) >= n);
buf = buf[0..<n]; buf = buf[0..n];
if a.count == 0 { if a.count == 0 {
buf[0] = '0'; buf[0] = '0';
return string(buf[0..<1]); return string(buf[0..1]);
} }
w := 0; w := 0;
if a.decimal_point <= 0 { if a.decimal_point <= 0 {
buf[w] = '0'; w++; buf[w] = '0'; w+=1;
buf[w] = '.'; w++; buf[w] = '.'; w+=1;
w += digit_zero(buf[w ..< w-a.decimal_point]); w += digit_zero(buf[w .. w-a.decimal_point]);
w += copy(buf[w..], a.digits[0..<a.count]); w += copy(buf[w..], a.digits[0..a.count]);
} else if a.decimal_point < a.count { } else if a.decimal_point < a.count {
w += copy(buf[w..], a.digits[0..<a.decimal_point]); w += copy(buf[w..], a.digits[0..a.decimal_point]);
buf[w] = '.'; w++; buf[w] = '.'; w+=1;
w += copy(buf[w..], a.digits[a.decimal_point ..< a.count]); w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
} else { } else {
w += copy(buf[w..], a.digits[0..<a.count]); w += copy(buf[w..], a.digits[0..a.count]);
w += digit_zero(buf[w ..< w+a.decimal_point-a.count]); w += digit_zero(buf[w .. w+a.decimal_point-a.count]);
} }
return string(buf[0..<w]); return string(buf[0..w]);
} }
// trim trailing zeros // trim trailing zeros
trim :: proc(a: ^Decimal) { trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' { for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--; a.count -= 1;
} }
if a.count == 0 { if a.count == 0 {
a.decimal_point = 0; a.decimal_point = 0;
@@ -59,34 +57,33 @@ trim :: proc(a: ^Decimal) {
assign :: proc(a: ^Decimal, i: u64) { assign :: proc(a: ^Decimal, i: u64) {
buf: [32]byte; buf: [32]u8;
n := 0; n := 0;
for i > 0 { for i > 0 {
j := i/10; j := i/10;
i -= 10*j; i -= 10*j;
buf[n] = byte('0'+i); buf[n] = u8('0'+i);
n++; n+=1;
i = j; i = j;
} }
a.count = 0; a.count = 0;
for n--; n >= 0; n-- { for n -= 1; n >= 0; n -= 1 {
a.digits[a.count] = buf[n]; a.digits[a.count] = buf[n];
a.count++; a.count+=1;
} }
a.decimal_point = a.count; a.decimal_point = a.count;
trim(a); trim(a);
} }
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
shift_right :: proc(a: ^Decimal, k: uint) { shift_right :: proc(a: ^Decimal, k: uint) {
r := 0; // read index r := 0; // read index
w := 0; // write index w := 0; // write index
n: uint; n: uint;
for ; n>>k == 0; r++ { for ; n>>k == 0; r+=1 {
if r >= a.count { if r >= a.count {
if n == 0 { if n == 0 {
// Just in case // Just in case
@@ -95,7 +92,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
} }
for n>>k == 0 { for n>>k == 0 {
n = n * 10; n = n * 10;
r++; r+=1;
} }
break; break;
} }
@@ -106,12 +103,12 @@ shift_right :: proc(a: ^Decimal, k: uint) {
mask: uint = (1<<k) - 1; mask: uint = (1<<k) - 1;
for ; r < a.count; r++ { for ; r < a.count; r+=1 {
c := uint(a.digits[r]); c := uint(a.digits[r]);
dig := n>>k; dig := n>>k;
n &= mask; n &= mask;
a.digits[w] = byte('0' + dig); a.digits[w] = u8('0' + dig);
w++; w+=1;
n = n*10 + c - '0'; n = n*10 + c - '0';
} }
@@ -119,8 +116,8 @@ shift_right :: proc(a: ^Decimal, k: uint) {
dig := n>>k; dig := n>>k;
n &= mask; n &= mask;
if w < len(a.digits) { if w < len(a.digits) {
a.digits[w] = byte('0' + dig); a.digits[w] = u8('0' + dig);
w++; w+=1;
} else if dig > 0 { } else if dig > 0 {
a.trunc = true; a.trunc = true;
} }
@@ -139,13 +136,13 @@ shift_left :: proc(a: ^Decimal, k: uint) {
w := a.count+delta; // write index w := a.count+delta; // write index
n: uint; n: uint;
for r--; r >= 0; r-- { for r -= 1; r >= 0; r -= 1 {
n += (uint(a.digits[r]) - '0') << k; n += (uint(a.digits[r]) - '0') << k;
quo := n/10; quo := n/10;
rem := n - 10*quo; rem := n - 10*quo;
w--; w -= 1;
if w < len(a.digits) { if w < len(a.digits) {
a.digits[w] = byte('0' + rem); a.digits[w] = u8('0' + rem);
} else if rem != 0 { } else if rem != 0 {
a.trunc = true; a.trunc = true;
} }
@@ -155,9 +152,9 @@ shift_left :: proc(a: ^Decimal, k: uint) {
for n > 0 { for n > 0 {
quo := n/10; quo := n/10;
rem := n - 10*quo; rem := n - 10*quo;
w--; w -= 1;
if 0 <= w && w < len(a.digits) { if 0 <= w && w < len(a.digits) {
a.digits[w] = byte('0' + rem); a.digits[w] = u8('0' + rem);
} else if rem != 0 { } else if rem != 0 {
a.trunc = true; a.trunc = true;
} }
@@ -171,6 +168,9 @@ shift_left :: proc(a: ^Decimal, k: uint) {
} }
shift :: proc(a: ^Decimal, k: int) { shift :: proc(a: ^Decimal, k: int) {
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
match { match {
case a.count == 0: case a.count == 0:
// no need to update // no need to update
@@ -194,9 +194,7 @@ shift :: proc(a: ^Decimal, k: int) {
can_round_up :: proc(a: ^Decimal, nd: int) -> bool { can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false ; } if nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count { if a.digits[nd] == '5' && nd+1 == a.count {
if a.trunc { if a.trunc do return true;
return true;
}
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0; return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
} }
@@ -215,9 +213,9 @@ round :: proc(a: ^Decimal, nd: int) {
round_up :: proc(a: ^Decimal, nd: int) { round_up :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; } if nd < 0 || nd >= a.count { return; }
for i := nd-1; i >= 0; i-- { for i := nd-1; i >= 0; i -= 1 {
if c := a.digits[i]; c < '9' { if c := a.digits[i]; c < '9' {
a.digits[i]++; a.digits[i]+=1;
a.count = i+1; a.count = i+1;
return; return;
} }
@@ -226,7 +224,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
// Number is just 9s // Number is just 9s
a.digits[0] = '1'; a.digits[0] = '1';
a.count = 1; a.count = 1;
a.decimal_point++; a.decimal_point+=1;
} }
round_down :: proc(a: ^Decimal, nd: int) { round_down :: proc(a: ^Decimal, nd: int) {
@@ -241,17 +239,17 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
if a.decimal_point > 20 { if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff; return 0xffff_ffff_ffff_ffff;
} }
i: int; i: int = 0;
n: u64 = 0; n: u64 = 0;
m := min(a.decimal_point, a.count); m := min(a.decimal_point, a.count);
for i = 0; i < m; i++ { for ; i < m; i += 1 {
n = n*10 + u64(a.digits[i]-'0'); n = n*10 + u64(a.digits[i]-'0');
} }
for ; i < a.decimal_point; i++ { for ; i < a.decimal_point; i += 1 {
n *= 10; n *= 10;
} }
if can_round_up(a, a.decimal_point) { if can_round_up(a, a.decimal_point) {
n++; n+=1;
} }
return n; return n;
} }
+482 -510
View File
File diff suppressed because it is too large Load Diff
+21 -22
View File
@@ -1,11 +1,13 @@
crc32 :: proc(data: []byte) -> u32 { import "mem.odin";
crc32 :: proc(data: []u8) -> u32 {
result := ~u32(0); result := ~u32(0);
for b in data { for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff]; result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
} }
return ~result; return ~result;
} }
crc64 :: proc(data: []byte) -> u64 { crc64 :: proc(data: []u8) -> u64 {
result := ~u64(0); result := ~u64(0);
for b in data { for b in data {
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff]; result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
@@ -13,7 +15,7 @@ crc64 :: proc(data: []byte) -> u64 {
return ~result; return ~result;
} }
fnv32 :: proc(data: []byte) -> u32 { fnv32 :: proc(data: []u8) -> u32 {
h: u32 = 0x811c9dc5; h: u32 = 0x811c9dc5;
for b in data { for b in data {
h = (h * 0x01000193) ~ u32(b); h = (h * 0x01000193) ~ u32(b);
@@ -21,7 +23,7 @@ fnv32 :: proc(data: []byte) -> u32 {
return h; return h;
} }
fnv64 :: proc(data: []byte) -> u64 { fnv64 :: proc(data: []u8) -> u64 {
h: u64 = 0xcbf29ce484222325; h: u64 = 0xcbf29ce484222325;
for b in data { for b in data {
h = (h * 0x100000001b3) ~ u64(b); h = (h * 0x100000001b3) ~ u64(b);
@@ -29,7 +31,7 @@ fnv64 :: proc(data: []byte) -> u64 {
return h; return h;
} }
fnv32a :: proc(data: []byte) -> u32 { fnv32a :: proc(data: []u8) -> u32 {
h: u32 = 0x811c9dc5; h: u32 = 0x811c9dc5;
for b in data { for b in data {
h = (h ~ u32(b)) * 0x01000193; h = (h ~ u32(b)) * 0x01000193;
@@ -37,7 +39,7 @@ fnv32a :: proc(data: []byte) -> u32 {
return h; return h;
} }
fnv64a :: proc(data: []byte) -> u64 { fnv64a :: proc(data: []u8) -> u64 {
h: u64 = 0xcbf29ce484222325; h: u64 = 0xcbf29ce484222325;
for b in data { for b in data {
h = (h ~ u64(b)) * 0x100000001b3; h = (h ~ u64(b)) * 0x100000001b3;
@@ -45,7 +47,7 @@ fnv64a :: proc(data: []byte) -> u64 {
return h; return h;
} }
murmur32 :: proc(data: []byte) -> u32 { murmur32 :: proc(data: []u8) -> u32 {
c1_32: u32 : 0xcc9e2d51; c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593; c2_32: u32 : 0x1b873593;
@@ -55,7 +57,7 @@ murmur32 :: proc(data: []byte) -> u32 {
p1 := p + 4*nblocks; p1 := p + 4*nblocks;
for ; p < p1; p += 4 { for ; p < p1; p += 4 {
k1 := ^u32(p)^; k1 := (cast(^u32)p)^;
k1 *= c1_32; k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17); k1 = (k1 << 15) | (k1 >> 17);
@@ -67,7 +69,6 @@ murmur32 :: proc(data: []byte) -> u32 {
} }
tail := data[nblocks*4 ..]; tail := data[nblocks*4 ..];
k1: u32; k1: u32;
match len(tail)&3 { match len(tail)&3 {
case 3: case 3:
@@ -95,7 +96,7 @@ murmur32 :: proc(data: []byte) -> u32 {
return h1; return h1;
} }
murmur64 :: proc(data: []byte) -> u64 { murmur64 :: proc(data: []u8) -> u64 {
SEED :: 0x9747b28c; SEED :: 0x9747b28c;
when size_of(int) == 8 { when size_of(int) == 8 {
@@ -103,7 +104,7 @@ murmur64 :: proc(data: []byte) -> u64 {
r :: 47; r :: 47;
h: u64 = SEED ~ (u64(len(data)) * m); h: u64 = SEED ~ (u64(len(data)) * m);
data64 := slice_ptr(^u64(&data[0]), len(data)/size_of(u64)); data64 := mem.slice_ptr(cast(^u64)&data[0], len(data)/size_of(u64));
for _, i in data64 { for _, i in data64 {
k := data64[i]; k := data64[i];
@@ -139,14 +140,13 @@ murmur64 :: proc(data: []byte) -> u64 {
h1 := u32(SEED) ~ u32(len(data)); h1 := u32(SEED) ~ u32(len(data));
h2 := u32(SEED) >> 32; h2 := u32(SEED) >> 32;
data32 := mem.slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
data32 := slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
len := len(data); len := len(data);
i := 0; i := 0;
for len >= 8 { for len >= 8 {
k1, k2: u32; k1, k2: u32;
k1 = data32[i]; i++; k1 = data32[i]; i += 1;
k1 *= m; k1 *= m;
k1 ~= k1>>r; k1 ~= k1>>r;
k1 *= m; k1 *= m;
@@ -154,7 +154,7 @@ murmur64 :: proc(data: []byte) -> u64 {
h1 ~= k1; h1 ~= k1;
len -= 4; len -= 4;
k2 = data32[i]; i++; k2 = data32[i]; i += 1;
k2 *= m; k2 *= m;
k2 ~= k2>>r; k2 ~= k2>>r;
k2 *= m; k2 *= m;
@@ -165,7 +165,7 @@ murmur64 :: proc(data: []byte) -> u64 {
if len >= 4 { if len >= 4 {
k1: u32; k1: u32;
k1 = data32[i]; i++; k1 = data32[i]; i += 1;
k1 *= m; k1 *= m;
k1 ~= k1>>r; k1 ~= k1>>r;
k1 *= m; k1 *= m;
@@ -175,7 +175,7 @@ murmur64 :: proc(data: []byte) -> u64 {
} }
// TODO(bill): Fix this // TODO(bill): Fix this
#no_bounds_check data8 := slice_to_bytes(data32[i..])[0..<3]; #no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
match len { match len {
case 3: case 3:
h2 ~= u32(data8[2]) << 16; h2 ~= u32(data8[2]) << 16;
@@ -197,13 +197,12 @@ murmur64 :: proc(data: []byte) -> u64 {
h2 ~= h1>>19; h2 ~= h1>>19;
h2 *= m; h2 *= m;
h := cast(u64)(h1)<<32 | cast(u64)(h2); return u64(h1)<<32 | u64(h2);
return h;
} }
} }
immutable _crc32_table := [256]u32{ _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -269,7 +268,7 @@ immutable _crc32_table := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
}; };
immutable _crc64_table := [256]u64{ _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5, 0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a, 0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b, 0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+81 -80
View File
@@ -20,79 +20,86 @@ Vec2 :: [vector 2]f32;
Vec3 :: [vector 3]f32; Vec3 :: [vector 3]f32;
Vec4 :: [vector 4]f32; Vec4 :: [vector 4]f32;
Mat2 :: [2]Vec2; // Column major
Mat3 :: [3]Vec3; Mat2 :: [2][2]f32;
Mat4 :: [4]Vec4; Mat3 :: [3][3]f32;
Mat4 :: [4][4]f32;
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32"; Complex :: complex64;
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
sin :: proc(θ: f32) -> f32 #foreign __llvm_core "llvm.sin.f32"; foreign __llvm_core {
sin :: proc(θ: f64) -> f64 #foreign __llvm_core "llvm.sin.f64"; sqrt :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---;
sqrt :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---;
cos :: proc(θ: f32) -> f32 #foreign __llvm_core "llvm.cos.f32"; sin :: proc(θ: f32) -> f32 #link_name "llvm.sin.f32" ---;
cos :: proc(θ: f64) -> f64 #foreign __llvm_core "llvm.cos.f64"; sin :: proc(θ: f64) -> f64 #link_name "llvm.sin.f64" ---;
tan :: proc(θ: f32) -> f32 #inline { return sin(θ)/cos(θ); } cos :: proc(θ: f32) -> f32 #link_name "llvm.cos.f32" ---;
tan :: proc(θ: f64) -> f64 #inline { return sin(θ)/cos(θ); } cos :: proc(θ: f64) -> f64 #link_name "llvm.cos.f64" ---;
pow :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32"; pow :: proc(x, power: f32) -> f32 #link_name "llvm.pow.f32" ---;
pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64"; pow :: proc(x, power: f64) -> f64 #link_name "llvm.pow.f64" ---;
fmuladd :: proc(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32" ---;
fmuladd :: proc(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64" ---;
}
tan :: proc(θ: f32) -> f32 #inline do return sin(θ)/cos(θ);
tan :: proc(θ: f64) -> f64 #inline do return sin(θ)/cos(θ);
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; } lerp :: proc(a, b, t: f32) -> (x: f32) do return a*(1-t) + b*t;
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; } lerp :: proc(a, b, t: f64) -> (x: f64) do return a*(1-t) + b*t;
unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16"; sign :: proc(x: f32) -> f32 { if x >= 0 do return +1; return -1; }
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32"; sign :: proc(x: f64) -> f64 { if x >= 0 do return +1; return -1; }
bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
copy_sign :: proc(x, y: f32) -> f32 { copy_sign :: proc(x, y: f32) -> f32 {
ix := transmute(u32, x); ix := transmute(u32)x;
iy := transmute(u32, y); iy := transmute(u32)y;
ix &= 0x7fff_ffff; ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000; ix |= iy & 0x8000_0000;
return transmute(f32, ix); return transmute(f32)ix;
} }
copy_sign :: proc(x, y: f64) -> f64 { copy_sign :: proc(x, y: f64) -> f64 {
ix := transmute(u64, x); ix := transmute(u64)x;
iy := transmute(u64, y); iy := transmute(u64)y;
ix &= 0x7fff_ffff_ffff_ff; ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000; ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64, ix); return transmute(f64)ix;
} }
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } round :: proc(x: f32) -> f32 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } round :: proc(x: f64) -> f64 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
floor :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions floor :: proc(x: f32) -> f32 { if x >= 0 do return f32(i64(x)); return f32(i64(x-0.5)); } // TODO: Get accurate versions
floor :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions floor :: proc(x: f64) -> f64 { if x >= 0 do return f64(i64(x)); return f64(i64(x-0.5)); } // TODO: Get accurate versions
ceil :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); } // TODO: Get accurate versions ceil :: proc(x: f32) -> f32 { if x < 0 do return f32(i64(x)); return f32(i64(x+1)); }// TODO: Get accurate versions
ceil :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); } // TODO: Get accurate versions ceil :: proc(x: f64) -> f64 { if x < 0 do return f64(i64(x)); return f64(i64(x+1)); }// TODO: Get accurate versions
remainder :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; } remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
remainder :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; } remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
mod :: proc(x, y: f32) -> f32 { mod :: proc(x, y: f32) -> f32 {
result: f32;
y = abs(y); y = abs(y);
result := remainder(abs(x), y); result = remainder(abs(x), y);
if sign(result) < 0 { if sign(result) < 0 {
result += y; result += y;
} }
return copy_sign(result, x); return copy_sign(result, x);
} }
mod :: proc(x, y: f64) -> f64 { mod :: proc(x, y: f64) -> f64 {
result: f64;
y = abs(y); y = abs(y);
result := remainder(abs(x), y); result = remainder(abs(x), y);
if sign(result) < 0 { if sign(result) < 0 {
result += y; result += y;
} }
@@ -100,52 +107,46 @@ mod :: proc(x, y: f64) -> f64 {
} }
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; } to_radians :: proc(degrees: f32) -> f32 do return degrees * TAU / 360;
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; } to_degrees :: proc(radians: f32) -> f32 do return radians * 360 / TAU;
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; } dot :: proc(a, b: $T/[vector 2]$E) -> E { c := a*b; return c.x + c.y; }
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; } dot :: proc(a, b: $T/[vector 3]$E) -> E { c := a*b; return c.x + c.y + c.z; }
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; } dot :: proc(a, b: $T/[vector 4]$E) -> E { c := a*b; return c.x + c.y + c.z + c.w; }
cross :: proc(x, y: Vec3) -> Vec3 { cross :: proc(x, y: $T/[vector 3]$E) -> T {
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1); a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b; return T(a - b);
} }
mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); } mag :: proc(v: $T/[vector 2]$E) -> E do return sqrt(dot(v, v));
mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); } mag :: proc(v: $T/[vector 3]$E) -> E do return sqrt(dot(v, v));
mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); } mag :: proc(v: $T/[vector 4]$E) -> E do return sqrt(dot(v, v));
norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{mag(v)}; } norm :: proc(v: $T/[vector 2]$E) -> T do return v / mag(v);
norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{mag(v)}; } norm :: proc(v: $T/[vector 3]$E) -> T do return v / mag(v);
norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{mag(v)}; } norm :: proc(v: $T/[vector 4]$E) -> T do return v / mag(v);
norm0 :: proc(v: Vec2) -> Vec2 { norm0 :: proc(v: $T/[vector 2]$E) -> T {
m := mag(v); m := mag(v);
if m == 0 { if m == 0 do return 0;
return Vec2{0}; return v/m;
}
return v / Vec2{m};
} }
norm0 :: proc(v: Vec3) -> Vec3 { norm0 :: proc(v: $T/[vector 3]$E) -> T {
m := mag(v); m := mag(v);
if m == 0 { if m == 0 do return 0;
return Vec3{0}; return v/m;
}
return v / Vec3{m};
} }
norm0 :: proc(v: Vec4) -> Vec4 { norm0 :: proc(v: $T/[vector 4]$E) -> T {
m := mag(v); m := mag(v);
if m == 0 { if m == 0 do return 0;
return Vec4{0}; return v/m;
}
return v / Vec4{m};
} }
@@ -160,8 +161,8 @@ mat4_identity :: proc() -> Mat4 {
} }
mat4_transpose :: proc(m: Mat4) -> Mat4 { mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j in 0..<4 { for j in 0..4 {
for i in 0..<4 { for i in 0..4 {
m[i][j], m[j][i] = m[j][i], m[i][j]; m[i][j], m[j][i] = m[j][i], m[i][j];
} }
} }
@@ -170,8 +171,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
mul :: proc(a, b: Mat4) -> Mat4 { mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4; c: Mat4;
for j in 0..<4 { for j in 0..4 {
for i in 0..<4 { for i in 0..4 {
c[j][i] = a[0][i]*b[j][0] + c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] + a[1][i]*b[j][1] +
a[2][i]*b[j][2] + a[2][i]*b[j][2] +
@@ -213,6 +214,7 @@ inverse :: proc(m: Mat4) -> Mat4 {
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2]; sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1]; sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02); o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04); o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05); o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
@@ -273,7 +275,7 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
s := sin(angle_radians); s := sin(angle_radians);
a := norm(v); a := norm(v);
t := a * Vec3{1-c}; t := a * (1-c);
rot := mat4_identity(); rot := mat4_identity();
@@ -315,18 +317,18 @@ look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
s := norm(cross(f, up)); s := norm(cross(f, up));
u := cross(s, f); u := cross(s, f);
m: Mat4; return Mat4{
{+s.x, +u.x, -f.x, 0},
m[0] = Vec4{+s.x, +s.y, +s.z, 0}; {+s.y, +u.y, -f.y, 0},
m[1] = Vec4{+u.x, +u.y, +u.z, 0}; {+s.z, +u.z, -f.z, 0},
m[2] = Vec4{-f.x, -f.y, -f.z, 0}; {-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
m[3] = Vec4{dot(s, eye), dot(u, eye), dot(f, eye), 1}; };
return m;
} }
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 { perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: Mat4; m: Mat4;
tan_half_fovy := tan(0.5 * fovy); tan_half_fovy := tan(0.5 * fovy);
m[0][0] = 1.0 / (aspect*tan_half_fovy); m[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy); m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near); m[2][2] = -(far + near) / (far - near);
@@ -350,7 +352,6 @@ ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
F32_DIG :: 6; F32_DIG :: 6;
F32_EPSILON :: 1.192092896e-07; F32_EPSILON :: 1.192092896e-07;
F32_GUARD :: 0; F32_GUARD :: 0;
+98 -89
View File
@@ -1,38 +1,57 @@
#import "fmt.odin"; import (
#import "os.odin"; "fmt.odin";
"os.odin";
"raw.odin";
)
foreign __llvm_core {
swap :: proc(b: u16) -> u16 #link_name "llvm.bswap.i16" ---;
swap :: proc(b: u32) -> u32 #link_name "llvm.bswap.i32" ---;
swap :: proc(b: u64) -> u64 #link_name "llvm.bswap.i64" ---;
}
swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16"; set :: proc(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless {
swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
return __mem_set(data, value, len); return __mem_set(data, value, len);
} }
zero :: proc(data: rawptr, len: int) -> rawptr { zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless {
return __mem_zero(data, len); return __mem_zero(data, len);
} }
copy :: proc(dst, src: rawptr, len: int) -> rawptr { copy :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
return __mem_copy(dst, src, len); return __mem_copy(dst, src, len);
} }
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr { copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
return __mem_copy_non_overlapping(dst, src, len); return __mem_copy_non_overlapping(dst, src, len);
} }
compare :: proc(a, b: []byte) -> int { compare :: proc(a, b: []u8) -> int #cc_contextless {
return __mem_compare(&a[0], &b[0], min(len(a), len(b))); return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
} }
slice_ptr :: proc(ptr: ^$T, len: int) -> []T #cc_contextless {
assert(len >= 0);
slice := raw.Slice{data = ptr, len = len, cap = len};
return (cast(^[]T)&slice)^;
}
slice_ptr :: proc(ptr: ^$T, len, cap: int) -> []T #cc_contextless {
assert(0 <= len && len <= cap);
slice := raw.Slice{data = ptr, len = len, cap = cap};
return (cast(^[]T)&slice)^;
}
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; } slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless {
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; } s := cast(^raw.Slice)&slice;
gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; } s.len *= size_of(T);
terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; } s.cap *= size_of(T);
return (cast(^[]u8)s)^;
}
kilobytes :: proc(x: int) -> int #inline #cc_contextless { return (x) * 1024; }
megabytes :: proc(x: int) -> int #inline #cc_contextless { return kilobytes(x) * 1024; }
gigabytes :: proc(x: int) -> int #inline #cc_contextless { return megabytes(x) * 1024; }
terabytes :: proc(x: int) -> int #inline #cc_contextless { return gigabytes(x) * 1024; }
is_power_of_two :: proc(x: int) -> bool { is_power_of_two :: proc(x: int) -> bool {
if x <= 0 { if x <= 0 do return false;
return false;
}
return (x & (x-1)) == 0; return (x & (x-1)) == 0;
} }
@@ -42,35 +61,30 @@ align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
a := uint(align); a := uint(align);
p := uint(ptr); p := uint(ptr);
modulo := p & (a-1); modulo := p & (a-1);
if modulo != 0 { if modulo != 0 do p += a - modulo;
p += a - modulo;
}
return rawptr(p); return rawptr(p);
} }
Allocation_Header :: struct { AllocationHeader :: struct {
size: int, size: int;
} }
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) { allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
header.size = size; header.size = size;
ptr := ^int(header+1); ptr := cast(^uint)(header+1);
n := cast(^uint)data - ptr;
for i := 0; rawptr(ptr) < data; i++ { for i in 0..n {
(ptr+i)^ = -1; (ptr+i)^ = ~uint(0);
} }
} }
allocation_header :: proc(data: rawptr) -> ^Allocation_Header { allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
if data == nil { if data == nil do return nil;
return nil; p := cast(^uint)data;
} for (p-1)^ == ~uint(0) do p = (p-1);
p := ^int(data); return cast(^AllocationHeader)(p-1);
for (p-1)^ == -1 {
p = (p-1);
}
return ^Allocation_Header(p-1);
} }
@@ -78,35 +92,36 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
// Custom allocators // Custom allocators
Arena :: struct { Arena :: struct {
backing: Allocator, backing: Allocator;
offset: int, offset: int;
memory: []byte, memory: []u8;
temp_count: int, temp_count: int;
} }
Arena_Temp_Memory :: struct { ArenaTempMemory :: struct {
arena: ^Arena, arena: ^Arena;
original_count: int, original_count: int;
} }
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) { init_arena_from_memory :: proc(using a: ^Arena, data: []u8) {
backing = Allocator{}; backing = Allocator{};
memory = data[0..<0]; memory = data[..0];
temp_count = 0; temp_count = 0;
} }
init_arena_from_context :: proc(using a: ^Arena, size: int) { init_arena_from_context :: proc(using a: ^Arena, size: int) {
backing = context.allocator; backing = context.allocator;
memory = make([]byte, size); memory = make([]u8, size);
temp_count = 0; temp_count = 0;
} }
free_arena :: proc(using a: ^Arena) { destroy_arena :: proc(using a: ^Arena) {
if backing.procedure != nil { if backing.procedure != nil {
push_allocator backing { push_allocator backing {
free(memory); free(memory);
@@ -123,14 +138,14 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
}; };
} }
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
size, alignment: int, size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr { old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode; using Allocator.Mode;
arena := ^Arena(allocator_data); arena := cast(^Arena)allocator_data;
match mode { match mode {
case ALLOC: case Alloc:
total_size := size + alignment; total_size := size + alignment;
if arena.offset + total_size > len(arena.memory) { if arena.offset + total_size > len(arena.memory) {
@@ -144,33 +159,33 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
arena.offset += total_size; arena.offset += total_size;
return zero(ptr, size); return zero(ptr, size);
case FREE: case Free:
// NOTE(bill): Free all at once // NOTE(bill): Free all at once
// Use Arena_Temp_Memory if you want to free a block // Use ArenaTempMemory if you want to free a block
case FREE_ALL: case FreeAll:
arena.offset = 0; arena.offset = 0;
case RESIZE: case Resize:
return default_resize_align(old_memory, old_size, size, alignment); return default_resize_align(old_memory, old_size, size, alignment);
} }
return nil; return nil;
} }
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory { begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
tmp: Arena_Temp_Memory; tmp: ArenaTempMemory;
tmp.arena = a; tmp.arena = a;
tmp.original_count = len(a.memory); tmp.original_count = len(a.memory);
a.temp_count++; a.temp_count += 1;
return tmp; return tmp;
} }
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) { end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
assert(len(arena.memory) >= original_count); assert(len(arena.memory) >= original_count);
assert(arena.temp_count > 0); assert(arena.temp_count > 0);
arena.memory = arena.memory[0..<original_count]; arena.memory = arena.memory[..original_count];
arena.temp_count--; arena.temp_count -= 1;
} }
@@ -181,9 +196,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
align_of_type_info :: proc(type_info: ^Type_Info) -> int { align_of_type_info :: proc(type_info: ^Type_Info) -> int {
prev_pow2 :: proc(n: i64) -> i64 { prev_pow2 :: proc(n: i64) -> i64 {
if n <= 0 { if n <= 0 do return 0;
return 0;
}
n |= n >> 1; n |= n >> 1;
n |= n >> 2; n |= n >> 2;
n |= n >> 4; n |= n >> 4;
@@ -196,13 +209,15 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int); WORD_SIZE :: size_of(int);
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants? MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using Type_Info; using Type_Info;
match info in type_info { match info in type_info.variant {
case Named: case Named:
return align_of_type_info(info.base); return align_of_type_info(info.base);
case Integer: case Integer:
return info.size; return type_info.align;
case Rune:
return type_info.align;
case Float: case Float:
return info.size; return type_info.align;
case String: case String:
return WORD_SIZE; return WORD_SIZE;
case Boolean: case Boolean:
@@ -220,18 +235,16 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
case Slice: case Slice:
return WORD_SIZE; return WORD_SIZE;
case Vector: case Vector:
size := size_of_type_info(info.elem); size := size_of_type_info(info.elem);
count := int(max(prev_pow2(i64(info.count)), 1)); count := int(max(prev_pow2(i64(info.count)), 1));
total := size * count; total := size * count;
return clamp(total, 1, MAX_ALIGN); return clamp(total, 1, MAX_ALIGN);
case Tuple: case Tuple:
return info.align; return type_info.align;
case Struct: case Struct:
return info.align; return type_info.align;
case Union: case Union:
return info.align; return type_info.align;
case Raw_Union:
return info.align;
case Enum: case Enum:
return align_of_type_info(info.base); return align_of_type_info(info.base);
case Map: case Map:
@@ -249,13 +262,15 @@ align_formula :: proc(size, align: int) -> int {
size_of_type_info :: proc(type_info: ^Type_Info) -> int { size_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int); WORD_SIZE :: size_of(int);
using Type_Info; using Type_Info;
match info in type_info { match info in type_info.variant {
case Named: case Named:
return size_of_type_info(info.base); return size_of_type_info(info.base);
case Integer: case Integer:
return info.size; return type_info.size;
case Rune:
return type_info.size;
case Float: case Float:
return info.size; return type_info.size;
case String: case String:
return 2*WORD_SIZE; return 2*WORD_SIZE;
case Boolean: case Boolean:
@@ -268,9 +283,7 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
return WORD_SIZE; return WORD_SIZE;
case Array: case Array:
count := info.count; count := info.count;
if count == 0 { if count == 0 do return 0;
return 0;
}
size := size_of_type_info(info.elem); size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem); align := align_of_type_info(info.elem);
alignment := align_formula(size, align); alignment := align_formula(size, align);
@@ -281,19 +294,15 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
return 2*WORD_SIZE; return 2*WORD_SIZE;
case Vector: case Vector:
count := info.count; count := info.count;
if count == 0 { if count == 0 do return 0;
return 0;
}
size := size_of_type_info(info.elem); size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem); align := align_of_type_info(info.elem);
alignment := align_formula(size, align); alignment := align_formula(size, align);
return alignment*(count-1) + size; return alignment*(count-1) + size;
case Struct: case Struct:
return info.size; return type_info.size;
case Union: case Union:
return info.size; return type_info.size;
case Raw_Union:
return info.size;
case Enum: case Enum:
return size_of_type_info(info.base); return size_of_type_info(info.base);
case Map: case Map:
+97 -85
View File
@@ -1,116 +1,127 @@
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows"; foreign_system_library (
#foreign_system_library lib "gl" when ODIN_OS == "linux"; lib "opengl32.lib" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows"; lib "gl" when ODIN_OS == "linux";
#import "sys/wgl.odin" when ODIN_OS == "windows"; )
#load "opengl_constants.odin"; import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"sys/wgl.odin" when ODIN_OS == "windows";
)
import_load "opengl_constants.odin";
Clear :: proc(mask: u32) #foreign lib "glClear"; _ := compile_assert(ODIN_OS != "osx");
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
Begin :: proc(mode: i32) #foreign lib "glBegin"; foreign lib {
End :: proc() #foreign lib "glEnd"; Clear :: proc(mask: u32) #link_name "glClear" ---;
Finish :: proc() #foreign lib "glFinish"; ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
BlendFunc :: proc(sfactor, dfactor: i32) #foreign lib "glBlendFunc"; Begin :: proc(mode: i32) #link_name "glBegin" ---;
Enable :: proc(cap: i32) #foreign lib "glEnable"; End :: proc() #link_name "glEnd" ---;
Disable :: proc(cap: i32) #foreign lib "glDisable"; Finish :: proc() #link_name "glFinish" ---;
GenTextures :: proc(count: i32, result: ^u32) #foreign lib "glGenTextures"; BlendFunc :: proc(sfactor, dfactor: i32) #link_name "glBlendFunc" ---;
DeleteTextures:: proc(count: i32, result: ^u32) #foreign lib "glDeleteTextures"; Enable :: proc(cap: i32) #link_name "glEnable" ---;
TexParameteri :: proc(target, pname, param: i32) #foreign lib "glTexParameteri"; Disable :: proc(cap: i32) #link_name "glDisable" ---;
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign lib "glTexParameterf"; GenTextures :: proc(count: i32, result: ^u32) #link_name "glGenTextures" ---;
BindTexture :: proc(target: i32, texture: u32) #foreign lib "glBindTexture"; DeleteTextures :: proc(count: i32, result: ^u32) #link_name "glDeleteTextures"---;
LoadIdentity :: proc() #foreign lib "glLoadIdentity"; TexParameteri :: proc(target, pname, param: i32) #link_name "glTexParameteri" ---;
Viewport :: proc(x, y, width, height: i32) #foreign lib "glViewport"; TexParameterf :: proc(target: i32, pname: i32, param: f32) #link_name "glTexParameterf" ---;
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho"; BindTexture :: proc(target: i32, texture: u32) #link_name "glBindTexture" ---;
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f"; LoadIdentity :: proc() #link_name "glLoadIdentity" ---;
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f"; Viewport :: proc(x, y, width, height: i32) #link_name "glViewport" ---;
GetError :: proc() -> i32 #foreign lib "glGetError"; Ortho :: proc(left, right, bottom, top, near, far: f64) #link_name "glOrtho" ---;
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString"; Color3f :: proc(r, g, b: f32) #link_name "glColor3f" ---;
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv"; Vertex3f :: proc(x, y, z: f32) #link_name "glVertex3f" ---;
TexCoord2f :: proc(x, y: f32) #foreign lib "glTexCoord2f"; GetError :: proc() -> i32 #link_name "glGetError" ---;
TexImage2D :: proc(target, level, internal_format, GetString :: proc(name: i32) -> ^u8 #link_name "glGetString" ---;
width, height, border, GetIntegerv :: proc(name: i32, v: ^i32) #link_name "glGetIntegerv" ---;
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D"; TexCoord2f :: proc(x, y: f32) #link_name "glTexCoord2f" ---;
TexImage2D :: proc(target, level, internal_format,
width, height, border,
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D" ---;
}
_string_data :: proc(s: string) -> ^u8 #inline { return &s[0]; } _string_data :: proc(s: string) -> ^u8 #inline { return &s[0]; }
_libgl := win32.LoadLibraryA(_string_data("opengl32.dll\x00")); _libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
GetProcAddress :: proc(name: string) -> proc() #cc_c { get_proc_address :: proc(name: string) -> rawptr {
if name[len(name)-1] == 0 { if name[len(name)-1] == 0 {
name = name[0..<len(name)-1]; name = name[..len(name)-1];
} }
// NOTE(bill): null terminated // NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0); assert((&name[0] + len(name))^ == 0);
res := wgl.GetProcAddress(&name[0]); res := wgl.get_proc_address(&name[0]);
if res == nil { if res == nil {
res = win32.GetProcAddress(_libgl, &name[0]); res = win32.get_proc_address(_libgl, &name[0]);
} }
return res; return rawptr(res);
} }
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c; // Procedures
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c; GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c; GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c; GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c; DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c; BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c; BindVertexArray: proc(buffer: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c; DeleteVertexArrays: proc(count: i32, arrays: ^u32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c; BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c; DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c; DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c; MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c; UnmapBuffer: proc(target: i32) #cc_c;
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c; VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
EnableVertexAttribArray: proc(index: u32) #cc_c; EnableVertexAttribArray: proc(index: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c; CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c; ShaderSource: proc(shader: u32, count: u32, str: ^^u8, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c; CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c; CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c; AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c; DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c; DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c; LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c; UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c; DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c; GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c; GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c; GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c; GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c; ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c; GenerateMipmap: proc(target: i32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c; SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c; SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c; SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c; SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c; SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c; SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c; Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c; Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c; Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c; Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c; Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c; Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c; Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c; Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c; UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c;
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
init :: proc() { init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { set_proc_address :: proc(p: rawptr, name: string) #inline {
x := ^(proc() #cc_c)(p); x := cast(^rawptr)p;
x^ = GetProcAddress(name); x^ = get_proc_address(name);
} }
set_proc_address(&GenBuffers, "glGenBuffers\x00"); set_proc_address(&GenBuffers, "glGenBuffers\x00");
@@ -120,6 +131,7 @@ init :: proc() {
set_proc_address(&BindBuffer, "glBindBuffer\x00"); set_proc_address(&BindBuffer, "glBindBuffer\x00");
set_proc_address(&BindSampler, "glBindSampler\x00"); set_proc_address(&BindSampler, "glBindSampler\x00");
set_proc_address(&BindVertexArray, "glBindVertexArray\x00"); set_proc_address(&BindVertexArray, "glBindVertexArray\x00");
set_proc_address(&DeleteVertexArrays, "glDeleteVertexArrays\x00");
set_proc_address(&BufferData, "glBufferData\x00"); set_proc_address(&BufferData, "glBufferData\x00");
set_proc_address(&BufferSubData, "glBufferSubData\x00"); set_proc_address(&BufferSubData, "glBufferSubData\x00");
-2
View File
@@ -1,4 +1,3 @@
FALSE :: 0; FALSE :: 0;
TRUE :: 1; TRUE :: 1;
@@ -1382,4 +1381,3 @@ DEBUG_LOGGED_MESSAGES_ARB :: 0x9145;
DEBUG_SEVERITY_HIGH_ARB :: 0x9146; DEBUG_SEVERITY_HIGH_ARB :: 0x9146;
DEBUG_SEVERITY_MEDIUM_ARB :: 0x9147; DEBUG_SEVERITY_MEDIUM_ARB :: 0x9147;
DEBUG_SEVERITY_LOW_ARB :: 0x9148; DEBUG_SEVERITY_LOW_ARB :: 0x9148;
+49 -3
View File
@@ -1,3 +1,49 @@
#load "os_windows.odin" when ODIN_OS == "windows"; import_load (
#load "os_x.odin" when ODIN_OS == "osx"; "os_windows.odin" when ODIN_OS == "windows";
#load "os_linux.odin" when ODIN_OS == "linux"; "os_x.odin" when ODIN_OS == "osx";
"os_linux.odin" when ODIN_OS == "linux";
)
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, cast([]u8)str);
}
read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
fd, err := open(name, O_RDONLY, 0);
if err != 0 {
return nil, false;
}
defer close(fd);
length: i64;
if length, err = file_size(fd); err != 0 {
return nil, false;
}
if length <= 0 {
return nil, true;
}
data := make([]u8, int(length));
if data == nil {
return nil, false;
}
bytes_read, read_err := read(fd, data);
if read_err != 0 {
free(data);
return nil, false;
}
return data[0..bytes_read], true;
}
write_entire_file :: proc(name: string, data: []u8) -> (sucess: bool) {
fd, err := open(name, O_WRONLY, 0);
if err != 0 {
return false;
}
defer close(fd);
bytes_written, write_err := write(fd, data);
return write_err != 0;
}
+75 -105
View File
@@ -1,11 +1,13 @@
#import "fmt.odin"; foreign_system_library (
#import "strings.odin"; dl "dl";
libc "c";
)
import "strings.odin";
Handle :: i32; Handle :: i32;
File_Time :: u64; File_Time :: u64;
Errno :: i32; Errno :: i32;
// INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000; O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001; O_WRONLY :: 0x00001;
@@ -19,6 +21,8 @@ O_APPEND :: 0x00400;
O_SYNC :: 0x01000; O_SYNC :: 0x01000;
O_ASYNC :: 0x02000; O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000; O_CLOEXEC :: 0x80000;
SEEK_SET :: 0; SEEK_SET :: 0;
SEEK_CUR :: 1; SEEK_CUR :: 1;
SEEK_END :: 2; SEEK_END :: 2;
@@ -34,12 +38,12 @@ RTLD_BINDING_MASK :: 0x3;
RTLD_GLOBAL :: 0x100; RTLD_GLOBAL :: 0x100;
// "Argv" arguments converted to Odin strings // "Argv" arguments converted to Odin strings
immutable args := _alloc_command_line_arguments(); args := _alloc_command_line_arguments();
_File_Time :: struct #ordered { _File_Time :: struct #ordered {
seconds: i64, seconds: i64;
nanoseconds: i32, nanoseconds: i32;
reserved: i32, reserved: i32;
} }
// Translated from // Translated from
@@ -47,31 +51,30 @@ _File_Time :: struct #ordered {
// Validity is not guaranteed. // Validity is not guaranteed.
Stat :: struct #ordered { Stat :: struct #ordered {
device_id: u64, // ID of device containing file device_id: u64; // ID of device containing file
serial: u64, // File serial number serial: u64; // File serial number
nlink: u32, // Number of hard links nlink: u32; // Number of hard links
mode: u32, // Mode of the file mode: u32; // Mode of the file
uid: u32, // User ID of the file's owner uid: u32; // User ID of the file's owner
gid: u32, // Group ID of the file's group gid: u32; // Group ID of the file's group
_padding: i32, // 32 bits of padding _padding: i32; // 32 bits of padding
rdev: u64, // Device ID, if device rdev: u64; // Device ID, if device
size: i64, // Size of the file, in bytes size: i64; // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O block_size: i64; // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated blocks: i64; // Number of 512-byte blocks allocated
last_access: _File_Time, // Time of last access last_access: _File_Time; // Time of last access
modified: _File_Time, // Time of last modification modified: _File_Time; // Time of last modification
status_change: _File_Time, // Time of last status change status_change: _File_Time; // Time of last status change
_reserve1, _reserve1,
_reserve2, _reserve2,
_reserve3: i64, _reserve3: i64;
serial_numbe: u64, // File serial number...? Maybe. serial_numbe: u64; // File serial number...? Maybe.
_reserve4: i64, _reserve4: i64;
}; };
// File type // File type
S_IFMT :: 0170000; // Type of file mask S_IFMT :: 0170000; // Type of file mask
S_IFIFO :: 0010000; // Named pipe (fifo) S_IFIFO :: 0010000; // Named pipe (fifo)
S_IFCHR :: 0020000; // Character special S_IFCHR :: 0020000; // Character special
@@ -83,21 +86,18 @@ S_IFSOCK :: 0140000; // Socket
// File mode // File mode
// Read, write, execute/search by owner // Read, write, execute/search by owner
S_IRWXU :: 0000700; // RWX mask for owner S_IRWXU :: 0000700; // RWX mask for owner
S_IRUSR :: 0000400; // R for owner S_IRUSR :: 0000400; // R for owner
S_IWUSR :: 0000200; // W for owner S_IWUSR :: 0000200; // W for owner
S_IXUSR :: 0000100; // X for owner S_IXUSR :: 0000100; // X for owner
// Read, write, execute/search by group // Read, write, execute/search by group
S_IRWXG :: 0000070; // RWX mask for group S_IRWXG :: 0000070; // RWX mask for group
S_IRGRP :: 0000040; // R for group S_IRGRP :: 0000040; // R for group
S_IWGRP :: 0000020; // W for group S_IWGRP :: 0000020; // W for group
S_IXGRP :: 0000010; // X for group S_IXGRP :: 0000010; // X for group
// Read, write, execute/search by others // Read, write, execute/search by others
S_IRWXO :: 0000007; // RWX mask for other S_IRWXO :: 0000007; // RWX mask for other
S_IROTH :: 0000004; // R for other S_IROTH :: 0000004; // R for other
S_IWOTH :: 0000002; // W for other S_IWOTH :: 0000002; // W for other
@@ -107,42 +107,43 @@ S_ISUID :: 0004000; // Set user id on execution
S_ISGID :: 0002000; // Set group id on execution S_ISGID :: 0002000; // Set group id on execution
S_ISVTX :: 0001000; // Directory restrcted delete S_ISVTX :: 0001000; // Directory restrcted delete
S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; }
S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; }
S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; }
S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; }
S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; }
S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; }
S_ISSOCK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFSOCK;}
R_OK :: 4; // Test for read permission S_ISLNK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
W_OK :: 2; // Test for write permission S_ISREG :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
X_OK :: 1; // Test for execute permission S_ISDIR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
S_ISCHR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
S_ISBLK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
S_ISFIFO :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
S_ISSOCK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
F_OK :: 0; // Test for file existance F_OK :: 0; // Test for file existance
X_OK :: 1; // Test for execute permission
W_OK :: 2; // Test for write permission
R_OK :: 4; // Test for read permission
#foreign_system_library dl "dl"; foreign libc {
#foreign_system_library libc "c"; _unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
_unix_close :: proc(fd: Handle) -> i32 #link_name "close" ---;
_unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "read" ---;
_unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "write" ---;
_unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64" ---;
_unix_gettid :: proc() -> u64 #link_name "gettid" ---;
_unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #link_name "stat" ---;
_unix_access :: proc(path: ^u8, mask: int) -> i32 #link_name "access" ---;
_unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open"; _unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
_unix_close :: proc(fd: Handle) -> i32 #foreign libc "close"; _unix_free :: proc(ptr: rawptr) #link_name "free" ---;
_unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "read"; _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
_unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "write"; _unix_getenv :: proc(^u8) -> ^u8 #link_name "getenv" ---;
_unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #foreign libc "lseek64";
_unix_gettid :: proc() -> u64 #foreign libc "gettid";
_unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #foreign libc "stat";
_unix_access :: proc(path: ^u8, mask: int) -> i32 #foreign libc "access";
_unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc"; _unix_exit :: proc(status: int) #link_name "exit" ---;
_unix_free :: proc(ptr: rawptr) #foreign libc "free"; }
_unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc"; foreign dl {
_unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv"; _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
_unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
_unix_exit :: proc(status: int) #foreign libc "exit"; _unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
_unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
_unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen"; }
_unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
_unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
_unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
// TODO(zangent): Change this to just `open` when Bill fixes overloading. // TODO(zangent): Change this to just `open` when Bill fixes overloading.
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) { open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
@@ -156,7 +157,7 @@ open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
return handle, 0; return handle, 0;
} }
// NOTE(zangent): This is here for compatability reasons. Should this be here? // NOTE(zangent): This is here for compatability reasons. Should this be here?
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode); return open_simple(path, mode);
} }
@@ -164,12 +165,12 @@ close :: proc(fd: Handle) {
_unix_close(fd); _unix_close(fd);
} }
read :: proc(fd: Handle, data: []byte) -> (int, Errno) { read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
sz := _unix_read(fd, &data[0], len(data)); sz := _unix_read(fd, &data[0], len(data));
return sz, 0; return sz, 0;
} }
write :: proc(fd: Handle, data: []byte) -> (int, Errno) { write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
sz := _unix_write(fd, &data[0], len(data)); sz := _unix_write(fd, &data[0], len(data));
return sz, 0; return sz, 0;
} }
@@ -179,8 +180,16 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
return res, 0; return res, 0;
} }
file_size :: proc(fd: Handle) -> (i64, Errno) {
prev, _ := seek(fd, 0, SEEK_CUR);
size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
}
// NOTE(bill): Uses startup to initialize it // NOTE(bill): Uses startup to initialize it
stdin: Handle = 0; stdin: Handle = 0;
stdout: Handle = 1; stdout: Handle = 1;
stderr: Handle = 2; stderr: Handle = 2;
@@ -204,45 +213,6 @@ access :: proc(path: string, mask: int) -> bool #inline {
return _unix_access(cstr, mask) == 0; return _unix_access(cstr, mask) == 0;
} }
read_entire_file :: proc(name: string) -> ([]byte, bool) {
fd: Handle;
err: Errno;
size: i64;
fd, err = open_simple(name, O_RDONLY);
if(err != 0) {
fmt.println("Failed to open file.");
return nil, false;
}
defer close(fd);
// We have a file
size, err = seek(fd, 0, SEEK_END);
if(err != 0) {
fmt.println("Failed to seek to end of file.");
return nil, false;
}
_, err = seek(fd, 0, SEEK_SET);
if(err != 0) {
fmt.println("Failed to seek to beginning of file.");
return nil, false;
}
// We have a file size!
data := make([]u8, size+1);
if data == nil {
fmt.println("Failed to allocate file buffer.");
return nil, false;
}
read(fd, data);
data[size] = 0;
return data, true;
}
heap_alloc :: proc(size: int) -> rawptr { heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0); assert(size > 0);
return _unix_malloc(size); return _unix_malloc(size);
+139 -178
View File
@@ -1,13 +1,14 @@
#import win32 "sys/windows.odin"; import win32 "sys/windows.odin";
#import fmt "fmt.odin"; import "mem.odin";
Handle :: int; Handle :: int;
File_Time :: u64; File_Time :: u64;
Errno :: int;
INVALID_HANDLE: Handle : -1; INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000; O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001; O_WRONLY :: 0x00001;
O_RDWR :: 0x00002; O_RDWR :: 0x00002;
@@ -21,42 +22,42 @@ O_SYNC :: 0x01000;
O_ASYNC :: 0x02000; O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000; O_CLOEXEC :: 0x80000;
ERROR_NONE: Errno : 0; Errno :: int;
ERROR_FILE_NOT_FOUND: Errno : 2;
ERROR_PATH_NOT_FOUND: Errno : 3; ERROR_NONE: Errno : 0;
ERROR_ACCESS_DENIED: Errno : 5; ERROR_FILE_NOT_FOUND: Errno : 2;
ERROR_NO_MORE_FILES: Errno : 18; ERROR_PATH_NOT_FOUND: Errno : 3;
ERROR_HANDLE_EOF: Errno : 38; ERROR_ACCESS_DENIED: Errno : 5;
ERROR_NETNAME_DELETED: Errno : 64; ERROR_NO_MORE_FILES: Errno : 18;
ERROR_FILE_EXISTS: Errno : 80; ERROR_HANDLE_EOF: Errno : 38;
ERROR_BROKEN_PIPE: Errno : 109; ERROR_NETNAME_DELETED: Errno : 64;
ERROR_BUFFER_OVERFLOW: Errno : 111; ERROR_FILE_EXISTS: Errno : 80;
ERROR_INSUFFICIENT_BUFFER: Errno : 122; ERROR_BROKEN_PIPE: Errno : 109;
ERROR_MOD_NOT_FOUND: Errno : 126; ERROR_BUFFER_OVERFLOW: Errno : 111;
ERROR_PROC_NOT_FOUND: Errno : 127; ERROR_INSUFFICIENT_BUFFER: Errno : 122;
ERROR_DIR_NOT_EMPTY: Errno : 145; ERROR_MOD_NOT_FOUND: Errno : 126;
ERROR_ALREADY_EXISTS: Errno : 183; ERROR_PROC_NOT_FOUND: Errno : 127;
ERROR_ENVVAR_NOT_FOUND: Errno : 203; ERROR_DIR_NOT_EMPTY: Errno : 145;
ERROR_MORE_DATA: Errno : 234; ERROR_ALREADY_EXISTS: Errno : 183;
ERROR_OPERATION_ABORTED: Errno : 995; ERROR_ENVVAR_NOT_FOUND: Errno : 203;
ERROR_IO_PENDING: Errno : 997; ERROR_MORE_DATA: Errno : 234;
ERROR_NOT_FOUND: Errno : 1168; ERROR_OPERATION_ABORTED: Errno : 995;
ERROR_PRIVILEGE_NOT_HELD: Errno : 1314; ERROR_IO_PENDING: Errno : 997;
WSAEACCES: Errno : 10013; ERROR_NOT_FOUND: Errno : 1168;
WSAECONNRESET: Errno : 10054; ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
WSAEACCES: Errno : 10013;
WSAECONNRESET: Errno : 10054;
// Windows reserves errors >= 1<<29 for application use // Windows reserves errors >= 1<<29 for application use
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0; ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
// "Argv" arguments converted to Odin strings // "Argv" arguments converted to Odin strings
immutable args := _alloc_command_line_arguments(); args := _alloc_command_line_arguments();
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 { if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
access: u32; access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) { match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
@@ -90,52 +91,67 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
create_mode = win32.OPEN_ALWAYS; create_mode = win32.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC: case mode&O_TRUNC == O_TRUNC:
create_mode = win32.TRUNCATE_EXISTING; create_mode = win32.TRUNCATE_EXISTING;
default: case:
create_mode = win32.OPEN_EXISTING; create_mode = win32.OPEN_EXISTING;
} }
buf: [300]byte; buf: [300]u8;
copy(buf[..], []byte(path)); copy(buf[..], cast([]u8)path);
handle := Handle(win32.CreateFileA(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil)); handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE { if handle != INVALID_HANDLE do return handle, ERROR_NONE;
return handle, ERROR_NONE;
} err := Errno(win32.get_last_error());
err := win32.GetLastError(); return INVALID_HANDLE, err;
return INVALID_HANDLE, Errno(err);
} }
close :: proc(fd: Handle) { close :: proc(fd: Handle) {
win32.CloseHandle(win32.Handle(fd)); win32.close_handle(win32.Handle(fd));
} }
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []byte(str)); write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
} if len(data) == 0 do return 0, ERROR_NONE;
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 { single_write_length: i32;
return 0, ERROR_NONE; total_write: i64;
length := i64(len(data));
for total_write < length {
remaining := length - total_write;
MAX :: 1<<31-1;
to_write: i32 = min(i32(remaining), MAX);
e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
if single_write_length <= 0 || e == win32.FALSE {
err := Errno(win32.get_last_error());
return int(total_write), err;
}
total_write += i64(single_write_length);
} }
bytes_written: i32; return int(total_write), ERROR_NONE;
e := win32.WriteFile(win32.Handle(fd), &data[0], i32(len(data)), &bytes_written, nil);
if e == win32.FALSE {
err := win32.GetLastError();
return 0, Errno(err);
}
return int(bytes_written), ERROR_NONE;
} }
read :: proc(fd: Handle, data: []byte) -> (int, Errno) { read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 { if len(data) == 0 do return 0, ERROR_NONE;
return 0, ERROR_NONE;
single_read_length: i32;
total_read: i64;
length := i64(len(data));
for total_read < length {
remaining := length - total_read;
MAX :: 1<<32-1;
to_read: u32 = min(u32(remaining), MAX);
e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 || e == win32.FALSE {
err := Errno(win32.get_last_error());
return int(total_read), err;
}
total_read += i64(single_read_length);
} }
bytes_read: i32; return int(total_read), ERROR_NONE;
e := win32.ReadFile(win32.Handle(fd), &data[0], u32(len(data)), &bytes_read, nil);
if e == win32.FALSE {
err := win32.GetLastError();
return 0, Errno(err);
}
return int(bytes_read), ERROR_NONE;
} }
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
@@ -147,18 +163,27 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
} }
hi := i32(offset>>32); hi := i32(offset>>32);
lo := i32(offset); lo := i32(offset);
ft := win32.GetFileType(win32.Handle(fd)); ft := win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE { if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
return 0, ERROR_FILE_IS_PIPE;
} dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
dw_ptr := win32.SetFilePointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER { if dw_ptr == win32.INVALID_SET_FILE_POINTER {
err := win32.GetLastError(); err := Errno(win32.get_last_error());
return 0, Errno(err); return 0, err;
} }
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE; return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
} }
file_size :: proc(fd: Handle) -> (i64, Errno) {
length: i64;
err: Errno;
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
err = Errno(win32.get_last_error());
}
return length, err;
}
// NOTE(bill): Uses startup to initialize it // NOTE(bill): Uses startup to initialize it
stdin := get_std_handle(win32.STD_INPUT_HANDLE); stdin := get_std_handle(win32.STD_INPUT_HANDLE);
@@ -167,8 +192,8 @@ stderr := get_std_handle(win32.STD_ERROR_HANDLE);
get_std_handle :: proc(h: int) -> Handle { get_std_handle :: proc(h: int) -> Handle {
fd := win32.GetStdHandle(i32(h)); fd := win32.get_std_handle(i32(h));
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0); win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
return Handle(fd); return Handle(fd);
} }
@@ -179,7 +204,7 @@ get_std_handle :: proc(h: int) -> Handle {
last_write_time :: proc(fd: Handle) -> File_Time { last_write_time :: proc(fd: Handle) -> File_Time {
file_info: win32.By_Handle_File_Information; file_info: win32.By_Handle_File_Information;
win32.GetFileInformationByHandle(win32.Handle(fd), &file_info); win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
lo := File_Time(file_info.last_write_time.lo); lo := File_Time(file_info.last_write_time.lo);
hi := File_Time(file_info.last_write_time.hi); hi := File_Time(file_info.last_write_time.hi);
return lo | hi << 32; return lo | hi << 32;
@@ -188,13 +213,13 @@ last_write_time :: proc(fd: Handle) -> File_Time {
last_write_time_by_name :: proc(name: string) -> File_Time { last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.Filetime; last_write_time: win32.Filetime;
data: win32.File_Attribute_Data; data: win32.File_Attribute_Data;
buf: [1024]byte; buf: [1024]u8;
assert(len(buf) > len(name)); assert(len(buf) > len(name));
copy(buf[..], []byte(name)); copy(buf[..], cast([]u8)name);
if win32.GetFileAttributesExA(&buf[0], win32.GetFileExInfoStandard, &data) != 0 { if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
last_write_time = data.last_write_time; last_write_time = data.last_write_time;
} }
@@ -204,86 +229,33 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
} }
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[..], []byte(name));
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
return nil, false;
}
defer close(fd);
length: i64;
if ok := win32.GetFileSizeEx(win32.Handle(fd), &length) != 0; !ok {
return nil, false;
}
if length == 0 {
return nil, true;
}
data := make([]byte, length);
if data == nil {
return nil, false;
}
single_read_length: i32;
total_read: i64;
for total_read < length {
remaining := length - total_read;
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = u32(remaining);
} else {
to_read = MAX;
}
win32.ReadFile(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 {
free(data);
return nil, false;
}
total_read += i64(single_read_length);
}
return data, true;
}
heap_alloc :: proc(size: int) -> rawptr { heap_alloc :: proc(size: int) -> rawptr {
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size); return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
} }
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 { if new_size == 0 {
heap_free(ptr); heap_free(ptr);
return nil; return nil;
} }
if ptr == nil { if ptr == nil do return heap_alloc(new_size);
return heap_alloc(new_size);
} return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
} }
heap_free :: proc(ptr: rawptr) { heap_free :: proc(ptr: rawptr) {
if ptr == nil { if ptr == nil do return;
return; win32.heap_free(win32.get_process_heap(), 0, ptr);
}
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
} }
exit :: proc(code: int) { exit :: proc(code: int) {
win32.ExitProcess(u32(code)); win32.exit_process(u32(code));
} }
current_thread_id :: proc() -> int { current_thread_id :: proc() -> int {
return int(win32.GetCurrentThreadId()); return int(win32.get_current_thread_id());
} }
@@ -292,61 +264,50 @@ current_thread_id :: proc() -> int {
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc() -> []string {
alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string { alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
wstr_len := 0; wstr_len := 0;
for (wstr+wstr_len)^ != 0 { for (wstr+wstr_len)^ != 0 do wstr_len += 1;
wstr_len++;
}
len := 2*wstr_len-1; len := 2*wstr_len-1;
buf := make([]byte, len+1); buf := make([]u8, len+1);
str := slice_ptr(wstr, wstr_len+1); str := mem.slice_ptr(wstr, wstr_len+1);
i, j := 0, 0; i, j := 0, 0;
for str[j] != 0 { for str[j] != 0 {
match { match {
case str[j] < 0x80: case str[j] < 0x80:
if i+1 > len { if i+1 > len do return "";
return ""; buf[i] = u8(str[j]); i += 1;
} j += 1;
buf[i] = byte(str[j]); i++;
j++;
case str[j] < 0x800: case str[j] < 0x800:
if i+2 > len { if i+2 > len do return "";
return ""; buf[i] = u8(0xc0 + (str[j]>>6)); i += 1;
} buf[i] = u8(0x80 + (str[j]&0x3f)); i += 1;
buf[i] = byte(0xc0 + (str[j]>>6)); i++; j += 1;
buf[i] = byte(0x80 + (str[j]&0x3f)); i++;
j++;
case 0xd800 <= str[j] && str[j] < 0xdc00: case 0xd800 <= str[j] && str[j] < 0xdc00:
if i+4 > len { if i+4 > len do return "";
return ""; c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
} buf[i] = u8(0xf0 + (c >> 18)); i += 1;
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000; buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i += 1;
buf[i] = byte(0xf0 + (c >> 18)); i++; buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i += 1;
buf[i] = byte(0x80 + ((c >> 12) & 0x3f)); i++; buf[i] = u8(0x80 + ((c ) & 0x3f)); i += 1;
buf[i] = byte(0x80 + ((c >> 6) & 0x3f)); i++;
buf[i] = byte(0x80 + ((c ) & 0x3f)); i++;
j += 2; j += 2;
case 0xdc00 <= str[j] && str[j] < 0xe000: case 0xdc00 <= str[j] && str[j] < 0xe000:
return ""; return "";
default: case:
if i+3 > len { if i+3 > len do return "";
return ""; buf[i] = 0xe0 + u8 (str[j] >> 12); i += 1;
} buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i += 1;
buf[i] = 0xe0 + byte (str[j] >> 12); i++; buf[i] = 0x80 + u8((str[j] ) & 0x3f); i += 1;
buf[i] = 0x80 + byte((str[j] >> 6) & 0x3f); i++; j += 1;
buf[i] = 0x80 + byte((str[j] ) & 0x3f); i++;
j++;
} }
} }
return string(buf[0..<i]); return string(buf[..i]);
} }
arg_count: i32; arg_count: i32;
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count); arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
arg_list := make([]string, arg_count); arg_list := make([]string, int(arg_count));
for _, i in arg_list { for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
}
return arg_list; return arg_list;
} }
+75 -104
View File
@@ -1,14 +1,14 @@
#import "fmt.odin"; foreign_system_library (
#import "strings.odin"; dl "dl";
libc "c";
)
Handle :: i32; import "strings.odin";
File_Time :: u64;
Errno :: int;
// TODO(zangent): Find out how to make this work on x64 and x32. Handle :: i32;
AddressSize :: i64; File_Time :: u64;
Errno :: int;
// INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000; O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001; O_WRONLY :: 0x00001;
@@ -22,6 +22,8 @@ O_APPEND :: 0x00400;
O_SYNC :: 0x01000; O_SYNC :: 0x01000;
O_ASYNC :: 0x02000; O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000; O_CLOEXEC :: 0x80000;
SEEK_SET :: 0; SEEK_SET :: 0;
SEEK_CUR :: 1; SEEK_CUR :: 1;
SEEK_END :: 2; SEEK_END :: 2;
@@ -29,6 +31,8 @@ SEEK_DATA :: 3;
SEEK_HOLE :: 4; SEEK_HOLE :: 4;
SEEK_MAX :: SEEK_HOLE; SEEK_MAX :: SEEK_HOLE;
// NOTE(zangent): These are OS specific! // NOTE(zangent): These are OS specific!
// Do not mix these up! // Do not mix these up!
RTLD_LAZY :: 0x1; RTLD_LAZY :: 0x1;
@@ -39,39 +43,39 @@ RTLD_NODELETE :: 0x80;
RTLD_NOLOAD :: 0x10; RTLD_NOLOAD :: 0x10;
RTLD_FIRST :: 0x100; RTLD_FIRST :: 0x100;
args: [dynamic]string; args: [dynamic]string;
FileTime :: struct #ordered { _File_Time :: struct #ordered {
seconds: i64, seconds: i64;
nanoseconds: i64 nanoseconds: i64;
} }
Stat :: struct #ordered { Stat :: struct #ordered {
device_id : i32, // ID of device containing file device_id: i32; // ID of device containing file
mode : u16, // Mode of the file mode: u16; // Mode of the file
nlink : u16, // Number of hard links nlink: u16; // Number of hard links
serial : u64, // File serial number serial: u64; // File serial number
uid : u32, // User ID of the file's owner uid: u32; // User ID of the file's owner
gid : u32, // Group ID of the file's group gid: u32; // Group ID of the file's group
rdev : i32, // Device ID, if device rdev: i32; // Device ID, if device
last_access : FileTime, // Time of last access last_access: File_Time; // Time of last access
modified : FileTime, // Time of last modification modified: File_Time; // Time of last modification
status_change : FileTime, // Time of last status change status_change: File_Time; // Time of last status change
created : FileTime, // Time of creation created: File_Time; // Time of creation
size : i64, // Size of the file, in bytes size: i64; // Size of the file, in bytes
blocks : i64, // Number of blocks allocated for the file blocks: i64; // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O block_size: i32; // Optimal blocksize for I/O
flags : u32, // User-defined flags for the file flags: u32; // User-defined flags for the file
gen_num : u32, // File generation number ...? gen_num: u32; // File generation number ...?
_spare : i32, // RESERVED _spare: i32; // RESERVED
_reserve1, _reserve1,
_reserve2 : i64, // RESERVED _reserve2: i64; // RESERVED
}; };
// File type // File type
S_IFMT :: 0170000; // Type of file mask S_IFMT :: 0170000; // Type of file mask
S_IFIFO :: 0010000; // Named pipe (fifo) S_IFIFO :: 0010000; // Named pipe (fifo)
S_IFCHR :: 0020000; // Character special S_IFCHR :: 0020000; // Character special
@@ -83,21 +87,18 @@ S_IFSOCK :: 0140000; // Socket
// File mode // File mode
// Read, write, execute/search by owner // Read, write, execute/search by owner
S_IRWXU :: 0000700; // RWX mask for owner S_IRWXU :: 0000700; // RWX mask for owner
S_IRUSR :: 0000400; // R for owner S_IRUSR :: 0000400; // R for owner
S_IWUSR :: 0000200; // W for owner S_IWUSR :: 0000200; // W for owner
S_IXUSR :: 0000100; // X for owner S_IXUSR :: 0000100; // X for owner
// Read, write, execute/search by group // Read, write, execute/search by group
S_IRWXG :: 0000070; // RWX mask for group S_IRWXG :: 0000070; // RWX mask for group
S_IRGRP :: 0000040; // R for group S_IRGRP :: 0000040; // R for group
S_IWGRP :: 0000020; // W for group S_IWGRP :: 0000020; // W for group
S_IXGRP :: 0000010; // X for group S_IXGRP :: 0000010; // X for group
// Read, write, execute/search by others // Read, write, execute/search by others
S_IRWXO :: 0000007; // RWX mask for other S_IRWXO :: 0000007; // RWX mask for other
S_IROTH :: 0000004; // R for other S_IROTH :: 0000004; // R for other
S_IWOTH :: 0000002; // W for other S_IWOTH :: 0000002; // W for other
@@ -107,43 +108,43 @@ S_ISUID :: 0004000; // Set user id on execution
S_ISGID :: 0002000; // Set group id on execution S_ISGID :: 0002000; // Set group id on execution
S_ISVTX :: 0001000; // Directory restrcted delete S_ISVTX :: 0001000; // Directory restrcted delete
S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; } S_ISLNK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFLNK;
S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; } S_ISREG :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFREG;
S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; } S_ISDIR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFDIR;
S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; } S_ISCHR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFCHR;
S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; } S_ISBLK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFBLK;
S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; } S_ISFIFO :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFIFO;
S_ISSOCK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFSOCK;} S_ISSOCK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFSOCK;
R_OK :: 4; // Test for read permission R_OK :: 4; // Test for read permission
W_OK :: 2; // Test for write permission W_OK :: 2; // Test for write permission
X_OK :: 1; // Test for execute permission X_OK :: 1; // Test for execute permission
F_OK :: 0; // Test for file existance F_OK :: 0; // Test for file existance
#foreign_system_library dl "dl"; foreign libc {
#foreign_system_library libc "c"; unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
unix_close :: proc(handle: Handle) #link_name "close" ---;
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---;
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---;
unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---;
unix_gettid :: proc() -> u64 #link_name "gettid" ---;
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open"; unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
unix_close :: proc(handle: Handle) #foreign libc "close"; unix_free :: proc(ptr: rawptr) #link_name "free" ---;
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #foreign libc "read"; unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #foreign libc "write"; unix_getenv :: proc(^u8) -> ^u8 #link_name "getenv" ---;
unix_lseek :: proc(fs: Handle, offset: AddressSize, whence: int) -> AddressSize #foreign libc "lseek";
unix_gettid :: proc() -> u64 #foreign libc "gettid";
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #foreign libc "stat";
unix_access :: proc(path: ^u8, mask: int) -> int #foreign libc "access";
unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc"; unix_exit :: proc(status: int) #link_name "exit" ---;
unix_free :: proc(ptr: rawptr) #foreign libc "free"; }
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv";
unix_exit :: proc(status: int) #foreign libc "exit";
unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen";
unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
foreign dl {
unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading. // TODO(zangent): Change this to just `open` when Bill fixes overloading.
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) { open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
@@ -158,7 +159,7 @@ open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
} }
// NOTE(zangent): This is here for compatability reasons. Should this be here? // NOTE(zangent): This is here for compatability reasons. Should this be here?
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode); return open_simple(path, mode);
} }
@@ -166,7 +167,7 @@ close :: proc(fd: Handle) {
unix_close(fd); unix_close(fd);
} }
write :: proc(fd: Handle, data: []byte) -> (AddressSize, Errno) { write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1); assert(fd != -1);
bytes_written := unix_write(fd, &data[0], len(data)); bytes_written := unix_write(fd, &data[0], len(data));
@@ -176,7 +177,7 @@ write :: proc(fd: Handle, data: []byte) -> (AddressSize, Errno) {
return bytes_written, 0; return bytes_written, 0;
} }
read :: proc(fd: Handle, data: []byte) -> (AddressSize, Errno) { read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1); assert(fd != -1);
bytes_read := unix_read(fd, &data[0], len(data)); bytes_read := unix_read(fd, &data[0], len(data));
@@ -186,16 +187,24 @@ read :: proc(fd: Handle, data: []byte) -> (AddressSize, Errno) {
return bytes_read, 0; return bytes_read, 0;
} }
seek :: proc(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
assert(fd != -1); assert(fd != -1);
final_offset := unix_lseek(fd, offset, whence); final_offset := i64(unix_lseek(fd, offset, whence));
if(final_offset == -1) { if(final_offset == -1) {
return 0, 1; return 0, 1;
} }
return final_offset, 0; return final_offset, 0;
} }
file_size :: proc(fd: Handle) -> (i64, Errno) {
prev, _ := seek(fd, 0, SEEK_CUR);
size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return i64(size), err;
}
// NOTE(bill): Uses startup to initialize it // NOTE(bill): Uses startup to initialize it
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE); stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
@@ -221,44 +230,6 @@ access :: proc(path: string, mask: int) -> bool #inline {
return unix_access(cstr, mask) == 0; return unix_access(cstr, mask) == 0;
} }
read_entire_file :: proc(name: string) -> ([]byte, bool) {
handle, err := open_simple(name, O_RDONLY);
if(err != 0) {
fmt.println("Failed to open file.");
return nil, false;
}
defer(close(handle));
// We have a file!
size: AddressSize;
size, err = seek(handle, 0, SEEK_END);
if(err != 0) {
fmt.println("Failed to seek to end of file.");
return nil, false;
}
_, err = seek(handle, 0, SEEK_SET);
if(err != 0) {
fmt.println("Failed to seek to beginning of file.");
return nil, false;
}
// We have a file size!
data := make([]u8, size+1);
if data == nil {
fmt.println("Failed to allocate file buffer.");
return nil, false;
}
read(handle, data);
data[size] = 0;
return data, true;
}
heap_alloc :: proc(size: int) -> rawptr #inline { heap_alloc :: proc(size: int) -> rawptr #inline {
assert(size > 0); assert(size > 0);
return unix_malloc(size); return unix_malloc(size);
+16 -15
View File
@@ -1,27 +1,28 @@
Any :: struct #ordered { Any :: struct #ordered {
data: rawptr, data: rawptr;
type_info: ^Type_Info, type_info: ^Type_Info;
} };
String :: struct #ordered { String :: struct #ordered {
data: ^byte, data: ^u8;
len: int, len: int;
}; };
Slice :: struct #ordered { Slice :: struct #ordered {
data: rawptr, data: rawptr;
len: int, len: int;
cap: int, cap: int;
}; };
Dynamic_Array :: struct #ordered { Dynamic_Array :: struct #ordered {
data: rawptr, data: rawptr;
len: int, len: int;
cap: int, cap: int;
allocator: Allocator, allocator: Allocator;
}; };
Dynamic_Map :: struct #ordered { Map :: struct #ordered {
hashes: [dynamic]int, hashes: [dynamic]int;
entries: Dynamic_Array, entries: Dynamic_Array;
}; };
+213
View File
@@ -0,0 +1,213 @@
bubble_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..last_j {
if f(array[j], array[j+1]) > 0 {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
bubble_sort :: proc(array: $A/[]$T) {
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..last_j {
if array[j] > array[j+1] {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
quick_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for f(a[i], p) < 0 do i += 1;
for f(p, a[j]) < 0 do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0..i], f);
quick_sort(a[i..n], f);
}
quick_sort :: proc(array: $A/[]$T) {
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for a[i] < p do i += 1;
for p < a[j] do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0..i]);
quick_sort(a[i..n]);
}
_log2 :: proc(n: int) -> int {
res := 0;
for ; n != 0; n >>= 1 do res += 1;
return res;
}
merge_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..N1+N2 {
if j == N2 || i < N1 && j < N2 && f(arr1[i], arr2[j]) < 0 {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
assert(f != nil);
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M+1 {
for j in 0..a {
k := 2*j*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..], f);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..], f);
} else {
copy(arr2[b..N], arr1[b..N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
merge_sort :: proc(array: $A/[]$T) {
merge_slices :: proc(arr1, arr2, out: A) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..N1+N2 {
if j == N2 || i < N1 && j < N2 && arr1[i] < arr2[j] {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M+1 {
for j in 0..a {
k := 2*j*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..]);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..]);
} else {
copy(arr2[b..N], arr1[b..N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
compare_ints :: proc(a, b: int) -> int {
match delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_f32s :: proc(a, b: f32) -> int {
match delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_f64s :: proc(a, b: f64) -> int {
match delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_strings :: proc(a, b: string) -> int {
return __string_cmp(a, b);
}
+232 -122
View File
@@ -1,10 +1,9 @@
#import . "decimal.odin"; import . "decimal.odin";
#import "math.odin";
Int_Flag :: enum { Int_Flag :: enum {
PREFIX = 1<<0, Prefix = 1<<0,
PLUS = 1<<1, Plus = 1<<1,
SPACE = 1<<2, Space = 1<<2,
} }
@@ -18,7 +17,7 @@ parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
return false, false; return false, false;
} }
_digit_value :: proc(r: rune) -> (int) { _digit_value :: proc(r: rune) -> int {
ri := int(r); ri := int(r);
v: int = 16; v: int = 16;
match r { match r {
@@ -29,92 +28,215 @@ _digit_value :: proc(r: rune) -> (int) {
return v; return v;
} }
parse_i64 :: proc(s: string, base: int) -> i64 { parse_i128 :: proc(s: string) -> i128 {
result: i64; neg := false;
if len(s) > 1 {
match s[0] {
case '-':
neg = true;
s = s[1..];
case '+':
s = s[1..];
}
}
base: i128 = 10;
if len(s) > 2 && s[0] == '0' {
match s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
case 'z': base = 12; s = s[2..];
case 'x': base = 16; s = s[2..];
}
}
value: i128;
for r in s { for r in s {
v := _digit_value(r); if r == '_' {
continue;
}
v := i128(_digit_value(r));
if v >= base { if v >= base {
break; break;
} }
result *= i64(base); value *= base;
result += i64(v); value += v;
} }
return result;
if neg do return -value;
return value;
} }
parse_u64 :: proc(s: string, base: int) -> u64 {
result: u64; parse_u128 :: proc(s: string) -> u128 {
for r in s { neg := false;
v := _digit_value(r); if len(s) > 1 && s[0] == '+' {
if v >= base { s = s[1..];
break; }
base := u128(10);
if len(s) > 2 && s[0] == '0' {
match s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
case 'z': base = 12; s = s[2..];
case 'x': base = 16; s = s[2..];
} }
result *= u64(base);
result += u64(v);
} }
return result;
value: u128;
for r in s {
if r == '_' do continue;
v := u128(_digit_value(r));
if v >= base do break;
value *= base;
value += u128(v);
}
if neg do return -value;
return value;
} }
parse_int :: proc(s: string, base: int) -> int {
return int(parse_i64(s, base));
parse_int :: proc(s: string) -> int {
return int(parse_i128(s));
} }
parse_uint :: proc(s: string, base: int) -> uint { parse_uint :: proc(s: string, base: int) -> uint {
return uint(parse_u64(s, base)); return uint(parse_u128(s));
}
parse_f64 :: proc(s: string) -> f64 {
i := 0;
sign: f64 = 1;
match s[i] {
case '-': i += 1; sign = -1;
case '+': i += 1;
}
value: f64 = 0;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
v := _digit_value(r);
if v >= 10 do break;
value *= 10;
value += f64(v);
}
if s[i] == '.' {
pow10: f64 = 10;
i += 1;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
v := _digit_value(r);
if v >= 10 do break;
value += f64(v)/pow10;
pow10 *= 10;
}
}
frac := false;
scale: f64 = 1;
if s[i] == 'e' || s[i] == 'E' {
i += 1;
match s[i] {
case '-': i += 1; frac = true;
case '+': i += 1;
}
exp: u32 = 0;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
d := u32(_digit_value(r));
if d >= 10 do break;
exp = exp * 10 + d;
}
if exp > 308 { exp = 308; }
for exp >= 50 { scale *= 1e50; exp -= 50; }
for exp >= 8 { scale *= 1e8; exp -= 8; }
for exp > 0 { scale *= 10; exp -= 1; }
}
if frac do return sign * (value/scale);
return sign * (value*scale);
} }
append_bool :: proc(buf: []byte, b: bool) -> string { append_bool :: proc(buf: []u8, b: bool) -> string {
s := b ? "true" : "false"; if b {
append(buf, ..[]byte(s)); append(&buf, "true");
} else {
append(&buf, "false");
}
return string(buf); return string(buf);
} }
append_uint :: proc(buf: []byte, u: u64, base: int) -> string { append_uint :: proc(buf: []u8, u: u64, base: int) -> string {
return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0); return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
} }
append_int :: proc(buf: []byte, i: i64, base: int) -> string { append_int :: proc(buf: []u8, i: i64, base: int) -> string {
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0); return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
} }
itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, i64(i), 10); } itoa :: proc(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); }
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size)); return string(generic_ftoa(buf, f, fmt, prec, bit_size));
} }
Decimal_Slice :: struct { DecimalSlice :: struct {
digits: []byte, digits: []u8;
count: int, count: int;
decimal_point: int, decimal_point: int;
neg: bool, neg: bool;
} }
Float_Info :: struct { FloatInfo :: struct {
mantbits: uint, mantbits: uint;
expbits: uint, expbits: uint;
bias: int, bias: int;
} }
f32_info := Float_Info{23, 8, -127};
f64_info := Float_Info{52, 11, -1023}; _f16_info := FloatInfo{10, 5, -15};
_f32_info := FloatInfo{23, 8, -127};
_f64_info := FloatInfo{52, 11, -1023};
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte { generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
bits: u64; bits: u64;
flt: ^Float_Info; flt: ^FloatInfo;
match bit_size { match bit_size {
case 32: case 32:
bits = u64(transmute(u32, f32(val))); bits = u64(transmute(u32)f32(val));
flt = &f32_info; flt = &_f32_info;
case 64: case 64:
bits = transmute(u64, val); bits = transmute(u64)val;
flt = &f64_info; flt = &_f64_info;
default: case:
panic("strconv: invalid bit_size"); panic("strconv: invalid bit_size");
} }
neg := bits>>(flt.expbits+flt.mantbits) != 0; neg := bits>>(flt.expbits+flt.mantbits) != 0;
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1); exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
mant := bits & (u64(1) << flt.mantbits - 1); mant := bits & (u64(1) << flt.mantbits - 1);
match exp { match exp {
@@ -127,13 +249,13 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
} else { } else {
s = "+Inf"; s = "+Inf";
} }
append(buf, ..[]byte(s)); append(&buf, ...cast([]u8)s);
return buf; return buf;
case 0: // denormalized case 0: // denormalized
exp++; exp += 1;
default: case:
mant |= u64(1) << flt.mantbits; mant |= u64(1) << flt.mantbits;
} }
@@ -143,11 +265,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
d := &d_; d := &d_;
assign(d, mant); assign(d, mant);
shift(d, exp - int(flt.mantbits)); shift(d, exp - int(flt.mantbits));
digs: Decimal_Slice; digs: DecimalSlice;
shortest := prec < 0; shortest := prec < 0;
if shortest { if shortest {
round_shortest(d, mant, exp, flt); round_shortest(d, mant, exp, flt);
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
match fmt { match fmt {
case 'e', 'E': prec = digs.count-1; case 'e', 'E': prec = digs.count-1;
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0); case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
@@ -164,39 +286,39 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
round(d, prec); round(d, prec);
} }
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
} }
return format_digits(buf, shortest, neg, digs, prec, fmt); return format_digits(buf, shortest, neg, digs, prec, fmt);
} }
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte { format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
match fmt { match fmt {
case 'f', 'F': case 'f', 'F':
append(buf, neg ? '-' : '+'); append(&buf, neg ? '-' : '+');
// integer, padded with zeros when needed // integer, padded with zeros when needed
if digs.decimal_point > 0 { if digs.decimal_point > 0 {
m := min(digs.count, digs.decimal_point); m := min(digs.count, digs.decimal_point);
append(buf, ..digs.digits[0..<m]); append(&buf, ...digs.digits[..m]);
for ; m < digs.decimal_point; m++ { for ; m < digs.decimal_point; m += 1 {
append(buf, '0'); append(&buf, '0');
} }
} else { } else {
append(buf, '0'); append(&buf, '0');
} }
// fractional part // fractional part
if prec > 0 { if prec > 0 {
append(buf, '.'); append(&buf, '.');
for i in 0..prec { for i in 0..prec {
c: byte = '0'; c: u8 = '0';
if j := digs.decimal_point + i; 0 <= j && j < digs.count { if j := digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j]; c = digs.digits[j];
} }
append(buf, c); append(&buf, c);
} }
} }
@@ -211,14 +333,12 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
return buf; // TODO return buf; // TODO
} }
c: [2]byte; c := [2]u8{'%', fmt};
c[0] = '%'; append(&buf, ...c[..]);
c[1] = fmt;
append(buf, ..c[..]);
return buf; return buf;
} }
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) { round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
if mant == 0 { // If mantissa is zero, the number is zero if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0; d.count = 0;
return; return;
@@ -236,7 +356,7 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
return; return;
} }
upper_: Decimal; upper: = &upper_; upper_: Decimal; upper := &upper_;
assign(upper, 2*mant - 1); assign(upper, 2*mant - 1);
shift(upper, exp - int(flt.mantbits) - 1); shift(upper, exp - int(flt.mantbits) - 1);
@@ -249,19 +369,19 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
mantlo = 2*mant - 1; mantlo = 2*mant - 1;
explo = exp-1; explo = exp-1;
} }
lower_: Decimal; lower: = &lower_; lower_: Decimal; lower := &lower_;
assign(lower, 2*mantlo + 1); assign(lower, 2*mantlo + 1);
shift(lower, explo - int(flt.mantbits) - 1); shift(lower, explo - int(flt.mantbits) - 1);
inclusive := mant%2 == 0; inclusive := mant%2 == 0;
for i in 0..<d.count { for i in 0..d.count {
l: byte = '0'; // lower digit l: u8 = '0'; // lower digit
if i < lower.count { if i < lower.count {
l = lower.digits[i]; l = lower.digits[i];
} }
m := d.digits[i]; // middle digit m := d.digits[i]; // middle digit
u: byte = '0'; // upper digit u: u8 = '0'; // upper digit
if i < upper.count { if i < upper.count {
u = upper.digits[i]; u = upper.digits[i];
} }
@@ -286,10 +406,10 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
} }
MAX_BASE :: 32; MAX_BASE :: 32;
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz"; digits := "0123456789abcdefghijklmnopqrstuvwxyz";
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) { is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
neg := false; neg := false;
if is_signed { if is_signed {
match bit_size { match bit_size {
@@ -297,84 +417,74 @@ is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned
i := i8(u); i := i8(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u64(i); u = u128(i);
case 16: case 16:
i := i16(u); i := i16(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u64(i); u = u128(i);
case 32: case 32:
i := i32(u); i := i32(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u64(i); u = u128(i);
case 64: case 64:
i := i64(u); i := i64(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u64(i); u = u128(i);
default: case 128:
i := i128(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case:
panic("is_integer_negative: Unknown integer size"); panic("is_integer_negative: Unknown integer size");
} }
} }
return u, neg; return u, neg;
} }
append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
is_pow2 :: proc(x: i64) -> bool {
if (x <= 0) {
return false;
}
return x&(x-1) == 0;
}
if base < 2 || base > MAX_BASE { if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits"); panic("strconv: illegal base passed to append_bits");
} }
a: [65]byte;
i := len(a);
neg: bool; neg: bool;
a: [129]u8;
i := len(a);
u, neg = is_integer_negative(u, is_signed, bit_size); u, neg = is_integer_negative(u, is_signed, bit_size);
b := u128(base);
for b := u64(base); u >= b; { for u >= b {
i--; i-=1; a[i] = digits[uint(u % b)];
q := u / b; u /= b;
a[i] = digits[uint(u-q*b)];
u = q;
} }
i-=1; a[i] = digits[uint(u % b)];
i--; if flags&Int_Flag.Prefix != 0 {
a[i] = digits[uint(u)];
if flags&Int_Flag.PREFIX != 0 {
ok := true; ok := true;
match base { match base {
case 2: i--; a[i] = 'b'; case 2: i-=1; a[i] = 'b';
case 8: i--; a[i] = 'o'; case 8: i-=1; a[i] = 'o';
case 10: i--; a[i] = 'd'; case 10: i-=1; a[i] = 'd';
case 12: i--; a[i] = 'z'; case 12: i-=1; a[i] = 'z';
case 16: i--; a[i] = 'x'; case 16: i-=1; a[i] = 'x';
default: ok = false; case: ok = false;
} }
if ok { if ok {
i--; i-=1; a[i] = '0';
a[i] = '0';
} }
} }
if neg { if neg {
i--; a[i] = '-'; i-=1; a[i] = '-';
} else if flags&Int_Flag.PLUS != 0 { } else if flags&Int_Flag.Plus != 0 {
i--; a[i] = '+'; i-=1; a[i] = '+';
} else if flags&Int_Flag.SPACE != 0 { } else if flags&Int_Flag.Space != 0 {
i--; a[i] = ' '; i-=1; a[i] = ' ';
} }
append(&buf, ...a[i..]);
append(buf, ..a[i..]);
return string(buf); return string(buf);
} }
+16 -8
View File
@@ -1,14 +1,22 @@
new_c_string :: proc(s: string) -> ^byte { import "mem.odin";
c := make([]byte, len(s)+1);
copy(c, []byte(s)); new_string :: proc(s: string) -> string {
c := make([]u8, len(s)+1);
copy(c, cast([]u8)s);
c[len(s)] = 0;
return string(c[..len(s)]);
}
new_c_string :: proc(s: string) -> ^u8 {
c := make([]u8, len(s)+1);
copy(c, cast([]u8)s);
c[len(s)] = 0; c[len(s)] = 0;
return &c[0]; return &c[0];
} }
to_odin_string :: proc(c: ^byte) -> string { to_odin_string :: proc(c: ^u8) -> string {
if c == nil do return "";
len := 0; len := 0;
for (c+len)^ != 0 { for (c+len)^ != 0 do len+=1;
len++; return string(mem.slice_ptr(c, len));
}
return string(slice_ptr(c, len));
} }
+4 -2
View File
@@ -1,2 +1,4 @@
#load "sync_windows.odin" when ODIN_OS == "windows"; import_load (
#load "sync_linux.odin" when ODIN_OS == "linux"; "sync_windows.odin" when ODIN_OS == "windows";
"sync_linux.odin" when ODIN_OS == "linux";
)
+95
View File
@@ -0,0 +1,95 @@
import (
"atomics.odin";
"os.odin";
)
Semaphore :: struct {
// _handle: win32.Handle;
}
Mutex :: struct {
_semaphore: Semaphore;
_counter: i32;
_owner: i32;
_recursion: i32;
}
current_thread_id :: proc() -> i32 {
return i32(os.current_thread_id());
}
semaphore_init :: proc(s: ^Semaphore) {
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
// win32.CloseHandle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline {
semaphore_post(s, 1);
}
semaphore_wait :: proc(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion += 1;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion += 1;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion -= 1;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}
if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}
+122
View File
@@ -0,0 +1,122 @@
import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"atomics.odin";
)
Semaphore :: struct {
_handle: win32.Handle;
}
/*
Mutex :: struct {
_semaphore: Semaphore;
_counter: i32;
_owner: i32;
_recursion: i32;
}
*/
Mutex :: struct {
_critical_section: win32.Critical_Section;
}
current_thread_id :: proc() -> i32 {
return i32(win32.get_current_thread_id());
}
semaphore_init :: proc(s: ^Semaphore) {
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
win32.close_handle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.release_semaphore(s._handle, i32(count), nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_wait :: proc(s: ^Semaphore) {
win32.wait_for_single_object(s._handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count));
}
mutex_destroy :: proc(m: ^Mutex) {
win32.delete_critical_section(&m._critical_section);
}
mutex_lock :: proc(m: ^Mutex) {
win32.enter_critical_section(&m._critical_section);
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
return win32.try_enter_critical_section(&m._critical_section) != 0;
}
mutex_unlock :: proc(m: ^Mutex) {
win32.leave_critical_section(&m._critical_section);
}
/*
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}
if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}
*/
+73 -72
View File
@@ -1,82 +1,83 @@
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows"; foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
#import . "windows.odin"; import . "windows.odin";
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
CONTEXT_MINOR_VERSION_ARB :: 0x2092; CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
CONTEXT_FLAGS_ARB :: 0x2094; CONTEXT_MINOR_VERSION_ARB :: 0x2092;
CONTEXT_PROFILE_MASK_ARB :: 0x9126; CONTEXT_FLAGS_ARB :: 0x2094;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002; CONTEXT_PROFILE_MASK_ARB :: 0x9126;
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001; CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002; CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
Hglrc :: Handle; Hglrc :: Handle;
Color_Ref :: u32; Color_Ref :: u32;
Layer_Plane_Descriptor :: struct #ordered { Layer_Plane_Descriptor :: struct {
size: u16, size: u16;
version: u16, version: u16;
flags: u32, flags: u32;
pixel_type: byte, pixel_type: u8;
color_bits: byte, color_bits: u8;
red_bits: byte, red_bits: u8;
red_shift: byte, red_shift: u8;
green_bits: byte, green_bits: u8;
green_shift: byte, green_shift: u8;
blue_bits: byte, blue_bits: u8;
blue_shift: byte, blue_shift: u8;
alpha_bits: byte, alpha_bits: u8;
alpha_shift: byte, alpha_shift: u8;
accum_bits: byte, accum_bits: u8;
accum_red_bits: byte, accum_red_bits: u8;
accum_green_bits: byte, accum_green_bits: u8;
accum_blue_bits: byte, accum_blue_bits: u8;
accum_alpha_bits: byte, accum_alpha_bits: u8;
depth_bits: byte, depth_bits: u8;
stencil_bits: byte, stencil_bits: u8;
aux_buffers: byte, aux_buffers: u8;
layer_type: byte, layer_type: u8;
reserved: byte, reserved: u8;
transparent: Color_Ref, transparent: Color_Ref;
} }
Point_Float :: struct #ordered { Point_Float :: struct {x, y: f32};
x, y: f32,
Glyph_Metrics_Float :: struct {
black_box_x: f32;
black_box_y: f32;
glyph_origin: Point_Float;
cell_inc_x: f32;
cell_inc_y: f32;
} }
Glyph_Metrics_Float :: struct #ordered { Create_Context_Attribs_ARB_Type :: #type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
black_box_x: f32, Choose_Pixel_Format_ARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
black_box_y: f32, Swap_Interval_EXT_Type :: #type proc(interval: i32) -> bool #cc_c;
glyph_origin: Point_Float, Get_Extensions_String_ARB_Type :: #type proc(Hdc) -> ^u8 #cc_c;
cell_inc_x: f32,
cell_inc_y: f32, // Procedures
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
choose_pixel_format_arb: Choose_Pixel_Format_ARB_Type;
swap_interval_ext: Swap_Interval_EXT_Type;
get_extensions_string_arb: Get_Extensions_String_ARB_Type;
foreign opengl32 {
create_context :: proc(hdc: Hdc) -> Hglrc #link_name "wglCreateContext" ---;
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent" ---;
get_proc_address :: proc(c_str: ^u8) -> rawptr #link_name "wglGetProcAddress" ---;
delete_context :: proc(hglrc: Hglrc) -> Bool #link_name "wglDeleteContext" ---;
copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext" ---;
create_layer_context :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext" ---;
describe_layer_plane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #link_name "wglDescribeLayerPlane" ---;
get_current_context :: proc() -> Hglrc #link_name "wglGetCurrentContext" ---;
get_current_dc :: proc() -> Hdc #link_name "wglGetCurrentDC" ---;
get_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #link_name "wglGetLayerPaletteEntries" ---;
realize_layer_palette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette" ---;
set_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #link_name "wglSetLayerPaletteEntries" ---;
share_lists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists" ---;
swap_layer_buffers :: proc(hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers" ---;
use_font_bitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps" ---;
use_font_outlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #link_name "wglUseFontOutlines" ---;
} }
CreateContextAttribsARB_Type :: #type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
ChoosePixelFormatARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
SwapIntervalEXT_Type :: #type proc(interval : i32) -> bool #cc_c;
GetExtensionsStringARB_Type :: #type proc(Hdc) -> ^byte #cc_c;
CreateContextAttribsARB: CreateContextAttribsARB_Type;
ChoosePixelFormatARB: ChoosePixelFormatARB_Type;
SwapIntervalEXT: SwapIntervalEXT_Type;
GetExtensionsStringARB: GetExtensionsStringARB_Type;
CreateContext :: proc(hdc: Hdc) -> Hglrc #foreign opengl32 "wglCreateContext";
MakeCurrent :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #foreign opengl32 "wglMakeCurrent";
GetProcAddress :: proc(c_str: ^u8) -> Proc #foreign opengl32 "wglGetProcAddress";
DeleteContext :: proc(hglrc: Hglrc) -> Bool #foreign opengl32 "wglDeleteContext";
CopyContext :: proc(src, dst: Hglrc, mask: u32) -> Bool #foreign opengl32 "wglCopyContext";
CreateLayerContext :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #foreign opengl32 "wglCreateLayerContext";
DescribeLayerPlane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #foreign opengl32 "wglDescribeLayerPlane";
GetCurrentContext :: proc() -> Hglrc #foreign opengl32 "wglGetCurrentContext";
GetCurrentDC :: proc() -> Hdc #foreign opengl32 "wglGetCurrentDC";
GetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
RealizeLayerPalette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #foreign opengl32 "wglRealizeLayerPalette";
SetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
ShareLists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #foreign opengl32 "wglShareLists";
SwapLayerBuffers :: proc(hdc: Hdc, planes: u32) -> Bool #foreign opengl32 "wglSwapLayerBuffers";
UseFontBitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #foreign opengl32 "wglUseFontBitmaps";
UseFontOutlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #foreign opengl32 "wglUseFontOutlines";
+527 -425
View File
File diff suppressed because it is too large Load Diff
+76
View File
@@ -0,0 +1,76 @@
_ :: compile_assert(ODIN_OS == "windows");
import win32 "sys/windows.odin";
Thread :: struct {
using specific: Os_Specific;
procedure: Proc;
data: any;
user_index: int;
init_context: Context;
use_init_context: bool;
Proc :: #type proc(^Thread) -> int;
Os_Specific :: struct {
win32_thread: win32.Handle;
win32_thread_id: u32;
}
}
create :: proc(procedure: Thread.Proc) -> ^Thread {
win32_thread_id: u32;
__windows_thread_entry_proc :: proc(data: rawptr) -> i32 #cc_c {
if data == nil do return 0;
t := cast(^Thread)data;
c := context;
if t.use_init_context {
c = t.init_context;
}
exit := 0;
push_context c {
exit = t.procedure(t);
}
return cast(i32)exit;
}
win32_thread_proc := cast(rawptr)__windows_thread_entry_proc;
thread := new(Thread);
win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
if win32_thread == nil {
free(thread);
return nil;
}
thread.procedure = procedure;
thread.win32_thread = win32_thread;
thread.win32_thread_id = win32_thread_id;
return thread;
}
start :: proc(using thread: ^Thread) {
win32.resume_thread(win32_thread);
}
is_done :: proc(using thread: ^Thread) -> bool {
res := win32.wait_for_single_object(win32_thread, 0);
return res != win32.WAIT_TIMEOUT;
}
join :: proc(using thread: ^Thread) {
win32.wait_for_single_object(win32_thread, win32.INFINITE);
win32.close_handle(win32_thread);
win32_thread = win32.INVALID_HANDLE;
}
destroy :: proc(thread: ^Thread) {
join(thread);
free(thread);
}
+47 -42
View File
@@ -1,98 +1,103 @@
is_signed :: proc(info: ^Type_Info) -> bool { is_signed :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
match i in type_info_base(info) { match i in type_info_base(info).variant {
case Type_Info.Integer: return i.signed; case Type_Info.Integer: return i.signed;
case Type_Info.Float: return true; case Type_Info.Float: return true;
} }
return false; return false;
} }
is_integer :: proc(info: ^Type_Info) -> bool { is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Integer); _, ok := type_info_base(info).variant.(Type_Info.Integer);
return ok;
}
is_rune :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info.Rune);
return ok; return ok;
} }
is_float :: proc(info: ^Type_Info) -> bool { is_float :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Float); _, ok := type_info_base(info).variant.(Type_Info.Float);
return ok; return ok;
} }
is_complex :: proc(info: ^Type_Info) -> bool { is_complex :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Complex); _, ok := type_info_base(info).variant.(Type_Info.Complex);
return ok; return ok;
} }
is_any :: proc(info: ^Type_Info) -> bool { is_any :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Any); _, ok := type_info_base(info).variant.(Type_Info.Any);
return ok; return ok;
} }
is_string :: proc(info: ^Type_Info) -> bool { is_string :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.String); _, ok := type_info_base(info).variant.(Type_Info.String);
return ok; return ok;
} }
is_boolean :: proc(info: ^Type_Info) -> bool { is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Boolean); _, ok := type_info_base(info).variant.(Type_Info.Boolean);
return ok; return ok;
} }
is_pointer :: proc(info: ^Type_Info) -> bool { is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Pointer); _, ok := type_info_base(info).variant.(Type_Info.Pointer);
return ok; return ok;
} }
is_procedure :: proc(info: ^Type_Info) -> bool { is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Procedure); _, ok := type_info_base(info).variant.(Type_Info.Procedure);
return ok; return ok;
} }
is_array :: proc(info: ^Type_Info) -> bool { is_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Array); _, ok := type_info_base(info).variant.(Type_Info.Array);
return ok; return ok;
} }
is_dynamic_array :: proc(info: ^Type_Info) -> bool { is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Dynamic_Array); _, ok := type_info_base(info).variant.(Type_Info.Dynamic_Array);
return ok; return ok;
} }
is_dynamic_map :: proc(info: ^Type_Info) -> bool { is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Map); _, ok := type_info_base(info).variant.(Type_Info.Map);
return ok; return ok;
} }
is_slice :: proc(info: ^Type_Info) -> bool { is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Slice); _, ok := type_info_base(info).variant.(Type_Info.Slice);
return ok; return ok;
} }
is_vector :: proc(info: ^Type_Info) -> bool { is_vector :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Vector); _, ok := type_info_base(info).variant.(Type_Info.Vector);
return ok; return ok;
} }
is_tuple :: proc(info: ^Type_Info) -> bool { is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Tuple); _, ok := type_info_base(info).variant.(Type_Info.Tuple);
return ok; return ok;
} }
is_struct :: proc(info: ^Type_Info) -> bool { is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Struct); s, ok := type_info_base(info).variant.(Type_Info.Struct);
return ok; return ok && !s.is_raw_union;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Union);
return ok;
} }
is_raw_union :: proc(info: ^Type_Info) -> bool { is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Raw_Union); s, ok := type_info_base(info).variant.(Type_Info.Struct);
return ok && s.is_raw_union;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info.Union);
return ok; return ok;
} }
is_enum :: proc(info: ^Type_Info) -> bool { is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
_, ok := type_info_base(info).(^Type_Info.Enum); _, ok := type_info_base(info).variant.(Type_Info.Enum);
return ok; return ok;
} }
+5 -9
View File
@@ -29,20 +29,16 @@ encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
encode :: proc(d: []u16, s: []rune) { encode :: proc(d: []u16, s: []rune) {
n := len(s); n := len(s);
for r in s { for r in s do if r >= _surr_self do n += 1;
if r >= _surr_self {
n++;
}
}
max_n := min(len(d), n); max_n := min(len(d), n);
n = 0; n = 0;
for r in s { for r in s {
match r { match r {
case 0..<_surr1, _surr3..<_surr_self: case 0.._surr1, _surr3.._surr_self:
d[n] = u16(r); d[n] = u16(r);
n++; n += 1;
case _surr_self..MAX_RUNE: case _surr_self..MAX_RUNE:
r1, r2 := encode_surrogate_pair(r); r1, r2 := encode_surrogate_pair(r);
@@ -50,9 +46,9 @@ encode :: proc(d: []u16, s: []rune) {
d[n+1] = u16(r2); d[n+1] = u16(r2);
n += 2; n += 2;
default: case:
d[n] = u16(REPLACEMENT_CHAR); d[n] = u16(REPLACEMENT_CHAR);
n++; n += 1;
} }
} }
} }
+32 -36
View File
@@ -24,13 +24,13 @@ RUNE1_MAX :: 1<<7 - 1;
RUNE2_MAX :: 1<<11 - 1; RUNE2_MAX :: 1<<11 - 1;
RUNE3_MAX :: 1<<16 - 1; RUNE3_MAX :: 1<<16 - 1;
// The default lowest and highest continuation byte. // The default lowest and highest continuation byte.
LOCB :: 0b1000_0000; LOCB :: 0b1000_0000;
HICB :: 0b1011_1111; HICB :: 0b1011_1111;
Accept_Range :: struct { lo, hi: u8 } Accept_Range :: struct {lo, hi: u8};
immutable accept_ranges := [5]Accept_Range{ accept_ranges := [5]Accept_Range{
{0x80, 0xbf}, {0x80, 0xbf},
{0xa0, 0xbf}, {0xa0, 0xbf},
{0x80, 0x9f}, {0x80, 0x9f},
@@ -38,7 +38,7 @@ immutable accept_ranges := [5]Accept_Range{
{0x80, 0x8f}, {0x80, 0x8f},
}; };
immutable accept_sizes := [256]byte{ accept_sizes := [256]u8{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
@@ -58,17 +58,17 @@ immutable accept_sizes := [256]byte{
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
}; };
encode_rune :: proc(r: rune) -> ([4]byte, int) { encode_rune :: proc(r: rune) -> ([4]u8, int) {
buf: [4]byte; buf: [4]u8;
i := u32(r); i := u32(r);
mask: byte : 0x3f; mask: u8 : 0x3f;
if i <= 1<<7-1 { if i <= 1<<7-1 {
buf[0] = byte(r); buf[0] = u8(r);
return buf, 1; return buf, 1;
} }
if i <= 1<<11-1 { if i <= 1<<11-1 {
buf[0] = 0xc0 | byte(r>>6); buf[0] = 0xc0 | u8(r>>6);
buf[1] = 0x80 | byte(r) & mask; buf[1] = 0x80 | u8(r) & mask;
return buf, 2; return buf, 2;
} }
@@ -79,21 +79,21 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
} }
if i <= 1<<16-1 { if i <= 1<<16-1 {
buf[0] = 0xe0 | byte(r>>12); buf[0] = 0xe0 | u8(r>>12);
buf[1] = 0x80 | byte(r>>6) & mask; buf[1] = 0x80 | u8(r>>6) & mask;
buf[2] = 0x80 | byte(r) & mask; buf[2] = 0x80 | u8(r) & mask;
return buf, 3; return buf, 3;
} }
buf[0] = 0xf0 | byte(r>>18); buf[0] = 0xf0 | u8(r>>18);
buf[1] = 0x80 | byte(r>>12) & mask; buf[1] = 0x80 | u8(r>>12) & mask;
buf[2] = 0x80 | byte(r>>6) & mask; buf[2] = 0x80 | u8(r>>6) & mask;
buf[3] = 0x80 | byte(r) & mask; buf[3] = 0x80 | u8(r) & mask;
return buf, 4; return buf, 4;
} }
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune([]byte(s)); } decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]u8)s); }
decode_rune :: proc(s: []byte) -> (rune, int) { decode_rune :: proc(s: []u8) -> (rune, int) {
n := len(s); n := len(s);
if n < 1 { if n < 1 {
return RUNE_ERROR, 0; return RUNE_ERROR, 0;
@@ -132,8 +132,8 @@ decode_rune :: proc(s: []byte) -> (rune, int) {
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune([]byte(s)); } decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]u8)s); }
decode_last_rune :: proc(s: []byte) -> (rune, int) { decode_last_rune :: proc(s: []u8) -> (rune, int) {
r: rune; r: rune;
size: int; size: int;
start, end, limit: int; start, end, limit: int;
@@ -151,16 +151,12 @@ decode_last_rune :: proc(s: []byte) -> (rune, int) {
limit = max(end - UTF_MAX, 0); limit = max(end - UTF_MAX, 0);
start--; for start-=1; start >= limit; start-=1 {
for start >= limit { if rune_start(s[start]) do break;
if rune_start(s[start]) {
break;
}
start--;
} }
start = max(start, 0); start = max(start, 0);
r, size = decode_rune(s[start..<end]); r, size = decode_rune(s[start..end]);
if start+size != end { if start+size != end {
return RUNE_ERROR, 1; return RUNE_ERROR, 1;
} }
@@ -187,7 +183,7 @@ valid_string :: proc(s: string) -> bool {
for i := 0; i < n; { for i := 0; i < n; {
si := s[i]; si := s[i];
if si < RUNE_SELF { // ascii if si < RUNE_SELF { // ascii
i++; i += 1;
continue; continue;
} }
x := accept_sizes[si]; x := accept_sizes[si];
@@ -215,28 +211,28 @@ valid_string :: proc(s: string) -> bool {
return true; return true;
} }
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; } rune_start :: proc(b: u8) -> bool #inline { return b&0xc0 != 0x80; }
rune_count :: proc(s: string) -> int #inline { return rune_count([]byte(s)); } rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]u8)s); }
rune_count :: proc(s: []byte) -> int { rune_count :: proc(s: []u8) -> int {
count := 0; count := 0;
n := len(s); n := len(s);
for i := 0; i < n; { for i := 0; i < n; {
defer count++; defer count += 1;
si := s[i]; si := s[i];
if si < RUNE_SELF { // ascii if si < RUNE_SELF { // ascii
i++; i += 1;
continue; continue;
} }
x := accept_sizes[si]; x := accept_sizes[si];
if x == 0xf1 { if x == 0xf1 {
i++; i += 1;
continue; continue;
} }
size := int(x & 7); size := int(x & 7);
if i+size > n { if i+size > n {
i++; i += 1;
continue; continue;
} }
ar := accept_ranges[x>>4]; ar := accept_ranges[x>>4];
+4 -1
View File
@@ -1,7 +1,10 @@
@echo off @echo off
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1 set _NO_DEBUG_HEAP=1
set path=w:\Odin\misc;%path% set path=w:\Odin\misc;%path%
+102 -99
View File
@@ -1,98 +1,7 @@
#define ARRAY_GROW_FORMULA(x) (2*(x) + 8) #define ARRAY_GROW_FORMULA(x) (2*(x) + 8)
GB_STATIC_ASSERT(ARRAY_GROW_FORMULA(0) > 0); GB_STATIC_ASSERT(ARRAY_GROW_FORMULA(0) > 0);
#define Array(Type_) struct { \ #if 1
gbAllocator allocator; \
Type_ * e; \
isize count; \
isize capacity; \
}
typedef Array(void) ArrayVoid;
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
(x_)->allocator = (allocator_); \
(x_)->count = 0; \
(x_)->capacity = (init_capacity_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \
} while (0)
#define array_init_count(x_, allocator_, init_count_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
(x_)->allocator = (allocator_); \
(x_)->count = (init_count_); \
(x_)->capacity = (init_count_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \
} while (0)
#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0)
#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0)
#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0)
#define array_grow(x_, min_capacity_) do { \
isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \
if (new_capacity < (min_capacity_)) { \
new_capacity = (min_capacity_); \
} \
array_set_capacity(x_, new_capacity); \
} while (0)
#define array_add(x_, item_) do { \
if ((x_)->capacity < (x_)->count+1) { \
array_grow(x_, 0); \
} \
(x_)->e[(x_)->count++] = item_; \
} while (0)
#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0)
#define array_clear(x_) do { (x_)->count = 0; } while (0)
#define array_resize(x_, new_count_) do { \
if ((x_)->capacity < (new_count_)) { \
array_grow((x_), (new_count_)); \
} \
(x_)->count = (new_count_); \
} while (0)
#define array_reserve(x_, new_capacity_) do { \
if ((x_)->capacity < (new_capacity_)) { \
array_set_capacity((x_), (new_capacity_)); \
} \
} while (0)
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
ArrayVoid *x = cast(ArrayVoid *)ptr;
GB_ASSERT(ptr != NULL);
GB_ASSERT(element_size > 0);
if (capacity == x->capacity) {
return;
}
if (capacity < x->count) {
if (x->capacity < capacity) {
isize new_capacity = ARRAY_GROW_FORMULA(x->capacity);
if (new_capacity < capacity) {
new_capacity = capacity;
}
array__set_capacity(ptr, new_capacity, element_size);
}
x->count = capacity;
}
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
x->capacity = capacity;
}
#if 0
template <typename T> template <typename T>
struct Array { struct Array {
gbAllocator allocator; gbAllocator allocator;
@@ -101,12 +10,16 @@ struct Array {
isize capacity; isize capacity;
T &operator[](isize index) { T &operator[](isize index) {
GB_ASSERT_MSG(0 <= index && index < count, "Index out of bounds"); #if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index]; return data[index];
} }
T const &operator[](isize index) const { T const &operator[](isize index) const {
GB_ASSERT_MSG(0 <= index && index < count, "Index out of bounds"); #if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index]; return data[index];
} }
}; };
@@ -122,7 +35,6 @@ template <typename T> void array_reserve (Array<T> *array, isize capacit
template <typename T> void array_resize (Array<T> *array, isize count); template <typename T> void array_resize (Array<T> *array, isize count);
template <typename T> void array_set_capacity(Array<T> *array, isize capacity); template <typename T> void array_set_capacity(Array<T> *array, isize capacity);
template <typename T> template <typename T>
void array_init(Array<T> *array, gbAllocator a, isize init_capacity) { void array_init(Array<T> *array, gbAllocator a, isize init_capacity) {
array->allocator = a; array->allocator = a;
@@ -152,7 +64,7 @@ Array<T> array_make(T *data, isize count, isize capacity) {
template <typename T> template <typename T>
void array_free(Array<T> *array) { void array_free(Array<T> *array) {
if (array->allocator.proc != NULL) { if (array->allocator.proc != nullptr) {
gb_free(array->allocator, array->data); gb_free(array->allocator, array->data);
} }
array->count = 0; array->count = 0;
@@ -214,7 +126,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
array_resize(array, capacity); array_resize(array, capacity);
} }
T *new_data = NULL; T *new_data = nullptr;
if (capacity > 0) { if (capacity > 0) {
new_data = gb_alloc_array(array->allocator, T, capacity); new_data = gb_alloc_array(array->allocator, T, capacity);
gb_memmove(new_data, array->data, gb_size_of(T) * array->capacity); gb_memmove(new_data, array->data, gb_size_of(T) * array->capacity);
@@ -224,6 +136,97 @@ void array_set_capacity(Array<T> *array, isize capacity) {
array->capacity = capacity; array->capacity = capacity;
} }
#endif #endif
#if 0
#define Array(Type_) struct { \
gbAllocator allocator; \
Type_ * e; \
isize count; \
isize capacity; \
}
typedef Array(void) ArrayVoid;
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != nullptr); \
(x_)->allocator = (allocator_); \
(x_)->count = 0; \
(x_)->capacity = (init_capacity_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \
} while (0)
#define array_init_count(x_, allocator_, init_count_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != nullptr); \
(x_)->allocator = (allocator_); \
(x_)->count = (init_count_); \
(x_)->capacity = (init_count_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \
} while (0)
#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0)
#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0)
#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0)
#define array_grow(x_, min_capacity_) do { \
isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \
if (new_capacity < (min_capacity_)) { \
new_capacity = (min_capacity_); \
} \
array_set_capacity(x_, new_capacity); \
} while (0)
#define array_add(x_, item_) do { \
if ((x_)->capacity < (x_)->count+1) { \
array_grow(x_, 0); \
} \
(x_)->e[(x_)->count++] = item_; \
} while (0)
#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0)
#define array_clear(x_) do { (x_)->count = 0; } while (0)
#define array_resize(x_, new_count_) do { \
if ((x_)->capacity < (new_count_)) { \
array_grow((x_), (new_count_)); \
} \
(x_)->count = (new_count_); \
} while (0)
#define array_reserve(x_, new_capacity_) do { \
if ((x_)->capacity < (new_capacity_)) { \
array_set_capacity((x_), (new_capacity_)); \
} \
} while (0)
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
ArrayVoid *x = cast(ArrayVoid *)ptr;
GB_ASSERT(ptr != nullptr);
GB_ASSERT(element_size > 0);
if (capacity == x->capacity) {
return;
}
if (capacity < x->count) {
if (x->capacity < capacity) {
isize new_capacity = ARRAY_GROW_FORMULA(x->capacity);
if (new_capacity < capacity) {
new_capacity = capacity;
}
array__set_capacity(ptr, new_capacity, element_size);
}
x->count = capacity;
}
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
x->capacity = capacity;
}
#endif
+170 -115
View File
@@ -1,5 +1,5 @@
// This stores the information for the specify architecture of this build // This stores the information for the specify architecture of this build
typedef struct BuildContext { struct BuildContext {
// Constants // Constants
String ODIN_OS; // target operating system String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture String ODIN_ARCH; // target architecture
@@ -12,16 +12,26 @@ typedef struct BuildContext {
i64 word_size; // Size of a pointer, must be >= 4 i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size) i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
String opt_flags;
String llc_flags; String llc_flags;
String link_flags; String link_flags;
bool is_dll; bool is_dll;
} BuildContext; bool generate_docs;
i32 optimization_level;
bool show_timings;
bool keep_temp_files;
gbAffinity affinity;
isize thread_count;
};
gb_global BuildContext build_context = {0}; gb_global BuildContext build_context = {0};
// TODO(bill): OS dependent versions for the BuildContext // TODO(bill): OS dependent versions for the BuildContext
// join_path // join_path
// is_dir // is_dir
@@ -35,7 +45,7 @@ String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
String odin_root_dir(void) { String odin_root_dir(void) {
String path = global_module_path; String path = global_module_path;
Array(wchar_t) path_buf; Array<wchar_t> path_buf;
isize len, i; isize len, i;
gbTempArenaMemory tmp; gbTempArenaMemory tmp;
wchar_t *text; wchar_t *text;
@@ -48,24 +58,30 @@ String odin_root_dir(void) {
len = 0; len = 0;
for (;;) { for (;;) {
len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count); len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
if (len == 0) { if (len == 0) {
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
if (len < path_buf.count) { if (len < path_buf.count) {
break; break;
} }
array_resize(&path_buf, 2*path_buf.count + 300); array_resize(&path_buf, 2*path_buf.count + 300);
} }
len += 1; // NOTE(bill): It needs an extra 1 for some reason
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
tmp = gb_temp_arena_memory_begin(&string_buffer_arena); tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
defer (gb_temp_arena_memory_end(tmp));
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetModuleFileNameW(NULL, text, len); GetModuleFileNameW(nullptr, text, cast(int)len);
path = string16_to_string(heap_allocator(), make_string16(text, len)); path = string16_to_string(heap_allocator(), make_string16(text, len));
for (i = path.len-1; i >= 0; i--) { for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i]; u8 c = path[i];
if (c == '/' || c == '\\') { if (c == '/' || c == '\\') {
break; break;
} }
@@ -75,7 +91,6 @@ String odin_root_dir(void) {
global_module_path = path; global_module_path = path;
global_module_path_set = true; global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf); array_free(&path_buf);
@@ -88,60 +103,7 @@ String odin_root_dir(void) {
String odin_root_dir(void) { String odin_root_dir(void) {
String path = global_module_path; String path = global_module_path;
Array(char) path_buf; Array<char> path_buf;
isize len, i;
gbTempArenaMemory tmp;
wchar_t *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
int sz = path_buf.count;
int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
if(res == 0) {
len = sz;
break;
} else {
array_resize(&path_buf, sz + 1);
}
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
// array_free(&path_buf);
return path;
}
#else
// NOTE: Linux / Unix is unfinished and not tested very well.
#include <sys/stat.h>
String odin_root_dir(void) {
String path = global_module_path;
Array(char) path_buf;
isize len, i; isize len, i;
gbTempArenaMemory tmp; gbTempArenaMemory tmp;
u8 *text; u8 *text;
@@ -154,28 +116,28 @@ String odin_root_dir(void) {
len = 0; len = 0;
for (;;) { for (;;) {
// This is not a 100% reliable system, but for the purposes u32 sz = path_buf.count;
// of this compiler, it should be _good enough_. int res = _NSGetExecutablePath(&path_buf[0], &sz);
// That said, there's no solid 100% method on Linux to get the program's if(res == 0) {
// path without checking this link. Sorry. len = sz;
len = readlink("/proc/self/exe", &path_buf.e[0], path_buf.count);
if(len == 0) {
return make_string(NULL, 0);
}
if (len < path_buf.count) {
break; break;
} else {
array_resize(&path_buf, sz + 1);
} }
array_resize(&path_buf, 2*path_buf.count + 300);
} }
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
tmp = gb_temp_arena_memory_begin(&string_buffer_arena); tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
defer (gb_temp_arena_memory_end(tmp));
text = gb_alloc_array(string_buffer_allocator, u8, len + 1); text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len); gb_memmove(text, &path_buf[0], len);
path = make_string(text, len); path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) { for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i]; u8 c = path[i];
if (c == '/' || c == '\\') { if (c == '/' || c == '\\') {
break; break;
} }
@@ -185,9 +147,67 @@ String odin_root_dir(void) {
global_module_path = path; global_module_path = path;
global_module_path_set = true; global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf); // array_free(&path_buf);
return path;
}
#else
// NOTE: Linux / Unix is unfinished and not tested very well.
#include <sys/stat.h>
String odin_root_dir(void) {
String path = global_module_path;
Array<char> path_buf;
isize len, i;
gbTempArenaMemory tmp;
u8 *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
defer (array_free(&path_buf));
len = 0;
for (;;) {
// This is not a 100% reliable system, but for the purposes
// of this compiler, it should be _good enough_.
// That said, there's no solid 100% method on Linux to get the program's
// path without checking this link. Sorry.
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
if(len == 0) {
return make_string(nullptr, 0);
}
if (len < path_buf.count) {
break;
}
array_resize(&path_buf, 2*path_buf.count + 300);
}
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
defer (gb_temp_arena_memory_end(tmp));
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
return path; return path;
} }
@@ -196,14 +216,17 @@ String odin_root_dir(void) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) { String path_to_fullpath(gbAllocator a, String s) {
String result = {};
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
String16 string16 = string_to_string16(string_buffer_allocator, s); String16 string16 = string_to_string16(string_buffer_allocator, s);
String result = {0};
DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL); DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
if (len != 0) { if (len != 0) {
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetFullPathNameW(string16.text, len, text, NULL); GetFullPathNameW(&string16[0], len, text, nullptr);
text[len] = 0; text[len] = 0;
result = string16_to_string(a, make_string16(text, len)); result = string16_to_string(a, make_string16(text, len));
} }
@@ -212,9 +235,11 @@ String path_to_fullpath(gbAllocator a, String s) {
} }
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
String path_to_fullpath(gbAllocator a, String s) { String path_to_fullpath(gbAllocator a, String s) {
char *p = realpath(cast(char *)s.text, 0); char *p;
if(p == NULL) return make_string_c(""); gb_mutex_lock(&string_buffer_mutex);
p = realpath(cast(char *)s.text, 0);
gb_mutex_unlock(&string_buffer_mutex);
if(p == nullptr) return make_string_c("");
return make_string_c(p); return make_string_c(p);
} }
#else #else
@@ -229,8 +254,8 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
isize i = 0; isize i = 0;
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len; gb_memmove(str+i, &base_dir[0], base_dir.len); i += base_dir.len;
gb_memmove(str+i, path.text, path.len); gb_memmove(str+i, &path[0], path.len);
str[str_len] = '\0'; str[str_len] = '\0';
res = path_to_fullpath(a, make_string(str, str_len)); res = path_to_fullpath(a, make_string(str, str_len));
gb_free(heap_allocator(), str); gb_free(heap_allocator(), str);
@@ -247,9 +272,9 @@ String get_fullpath_core(gbAllocator a, String path) {
isize str_len = module_dir.len + core_len + path.len; isize str_len = module_dir.len + core_len + path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1); u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
gb_memmove(str, module_dir.text, module_dir.len); gb_memmove(str, &module_dir[0], module_dir.len);
gb_memmove(str+module_dir.len, core, core_len); gb_memmove(str+module_dir.len, core, core_len);
gb_memmove(str+module_dir.len+core_len, path.text, path.len); gb_memmove(str+module_dir.len+core_len, &path[0], path.len);
str[str_len] = '\0'; str[str_len] = '\0';
res = path_to_fullpath(a, make_string(str, str_len)); res = path_to_fullpath(a, make_string(str, str_len));
@@ -258,71 +283,101 @@ String get_fullpath_core(gbAllocator a, String path) {
} }
String const ODIN_VERSION = str_lit("0.6.2");
void init_build_context(void) { void init_build_context(void) {
BuildContext *bc = &build_context; BuildContext *bc = &build_context;
gb_affinity_init(&bc->affinity);
if (bc->thread_count == 0) {
bc->thread_count = gb_max(bc->affinity.thread_count, 1);
}
bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.2.0"); bc->ODIN_VERSION = ODIN_VERSION;
bc->ODIN_ROOT = odin_root_dir(); bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
bc->ODIN_OS = str_lit("windows"); bc->ODIN_OS = str_lit("windows");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#elif defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_OSX)
bc->ODIN_OS = str_lit("osx"); bc->ODIN_OS = str_lit("osx");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#else #else
bc->ODIN_OS = str_lit("linux"); bc->ODIN_OS = str_lit("linux");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#endif #endif
#if defined(GB_ARCH_64_BIT)
bc->ODIN_ARCH = str_lit("amd64");
#else
bc->ODIN_ARCH = str_lit("x86");
#endif
{
u16 x = 1;
bool big = !(*cast(u8 *)&x);
bc->ODIN_ENDIAN = big ? str_lit("big") : str_lit("little");
}
// NOTE(zangent): The linker flags to set the build architecture are different // NOTE(zangent): The linker flags to set the build architecture are different
// across OSs. It doesn't make sense to allocate extra data on the heap // across OSs. It doesn't make sense to allocate extra data on the heap
// here, so I just #defined the linker flags to keep things concise. // here, so I just #defined the linker flags to keep things concise.
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
#define LINK_FLAG_X64 "/machine:x64"
#define LINK_FLAG_X64 "/machine:x64" #define LINK_FLAG_X86 "/machine:x86"
#define LINK_FLAG_X86 "/machine:x86"
#elif defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_OSX)
// NOTE(zangent): MacOS systems are x64 only, so ld doesn't have
// an architecture option. All compilation done on MacOS must be x64.
GB_ASSERT(bc->ODIN_ARCH == "amd64");
// NOTE(zangent): MacOS systems are x64 only, so ld doesn't have #define LINK_FLAG_X64 ""
// an architecture option. All compilation done on MacOS must be x64. #define LINK_FLAG_X86 ""
GB_ASSERT(str_eq(bc->ODIN_ARCH, str_lit("amd64")));
#define LINK_FLAG_X64 ""
#define LINK_FLAG_X86 ""
#else #else
// Linux, but also BSDs and the like. // Linux, but also BSDs and the like.
// NOTE(zangent): When clang is swapped out with ld as the linker, // NOTE(zangent): When clang is swapped out with ld as the linker,
// the commented flags here should be used. Until then, we'll have // the commented flags here should be used. Until then, we'll have
// to use alternative build flags made for clang. // to use alternative build flags made for clang.
/* /*
#define LINK_FLAG_X64 "-m elf_x86_64" #define LINK_FLAG_X64 "-m elf_x86_64"
#define LINK_FLAG_X86 "-m elf_i386" #define LINK_FLAG_X86 "-m elf_i386"
*/ */
#define LINK_FLAG_X64 "-arch x86-64" #define LINK_FLAG_X64 "-arch x86-64"
#define LINK_FLAG_X86 "-arch x86" #define LINK_FLAG_X86 "-arch x86"
#endif #endif
if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
if (bc->ODIN_ARCH == "amd64") {
bc->word_size = 8; bc->word_size = 8;
bc->max_align = 16; bc->max_align = 16;
bc->llc_flags = str_lit("-march=x86-64 "); bc->llc_flags = str_lit("-march=x86-64 ");
bc->link_flags = str_lit(LINK_FLAG_X64 " "); bc->link_flags = str_lit(LINK_FLAG_X64 " ");
} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) { } else if (bc->ODIN_ARCH == "x86") {
bc->word_size = 4; bc->word_size = 4;
bc->max_align = 8; bc->max_align = 8;
bc->llc_flags = str_lit("-march=x86 "); bc->llc_flags = str_lit("-march=x86 ");
bc->link_flags = str_lit(LINK_FLAG_X86 " "); bc->link_flags = str_lit(LINK_FLAG_X86 " ");
} else {
gb_printf_err("This current architecture is not supported");
gb_exit(1);
} }
isize opt_max = 1023;
char *opt_flags_string = gb_alloc_array(heap_allocator(), char, opt_max+1);
isize opt_len = 0;
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
if (bc->optimization_level != 0) {
opt_len = gb_snprintf(opt_flags_string, opt_max, "-O%d", bc->optimization_level);
} else {
opt_len = gb_snprintf(opt_flags_string, opt_max, "");
}
if (opt_len > 0) {
opt_len--;
}
bc->opt_flags = make_string(cast(u8 *)opt_flags_string, opt_len);
#undef LINK_FLAG_X64 #undef LINK_FLAG_X64
#undef LINK_FLAG_X86 #undef LINK_FLAG_X86
} }
-603
View File
@@ -1,603 +0,0 @@
bool check_is_terminating(AstNode *node);
void check_stmt (Checker *c, AstNode *node, u32 flags);
// NOTE(bill): `content_name` is for debugging and error messages
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
if (operand->mode == Addressing_Builtin) {
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
operand->mode = Addressing_Invalid;
gb_string_free(expr_str);
}
if (e->type == NULL) {
e->type = t_invalid;
}
return NULL;
}
if (e->type == NULL) {
// NOTE(bill): Use the type of the operand
Type *t = operand->type;
if (is_type_untyped(t)) {
if (t == t_invalid || is_type_untyped_nil(t)) {
error(e->token, "Use of untyped nil in %.*s", LIT(context_name));
e->type = t_invalid;
return NULL;
}
t = default_type(t);
}
GB_ASSERT(is_type_typed(t));
e->type = t;
}
check_assignment(c, operand, e->type, context_name);
if (operand->mode == Addressing_Invalid) {
return NULL;
}
return e->type;
}
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) {
if ((lhs == NULL || lhs_count == 0) && inits.count == 0) {
return;
}
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
check_unpack_arguments(c, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands.e[i].mode == Addressing_Invalid) {
rhs_count--;
}
}
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name);
}
if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
gb_temp_arena_memory_end(tmp);
}
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
if (e->type == NULL) {
e->type = t_invalid;
}
return;
}
if (operand->mode != Addressing_Constant) {
// TODO(bill): better error
gbString str = expr_to_string(operand->expr);
error_node(operand->expr, "`%s` is not a constant", str);
gb_string_free(str);
if (e->type == NULL) {
e->type = t_invalid;
}
return;
}
if (!is_type_constant_type(operand->type)) {
gbString type_str = type_to_string(operand->type);
error_node(operand->expr, "Invalid constant type: `%s`", type_str);
gb_string_free(type_str);
if (e->type == NULL) {
e->type = t_invalid;
}
return;
}
if (e->type == NULL) { // NOTE(bill): type inference
e->type = operand->type;
}
check_assignment(c, operand, e->type, str_lit("constant declaration"));
if (operand->mode == Addressing_Invalid) {
return;
}
e->Constant.value = operand->value;
}
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
GB_ASSERT(e->type == NULL);
Type *named = make_type_named(c->allocator, e->token.string, NULL, e);
named->Named.type_name = e;
if (def != NULL && def->kind == Type_Named) {
def->Named.base = named;
}
e->type = named;
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
Type *bt = check_type_extra(c, type_expr, named);
named->Named.base = base_type(bt);
if (named->Named.base == t_invalid) {
// gb_printf("check_type_decl: %s\n", type_to_string(named));
}
}
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->kind == Entity_Constant);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
if (type_expr) {
Type *t = check_type(c, type_expr);
if (!is_type_constant_type(t)) {
gbString str = type_to_string(t);
error_node(type_expr, "Invalid constant type `%s`", str);
gb_string_free(str);
e->type = t_invalid;
return;
}
e->type = t;
}
Operand operand = {0};
if (init != NULL) {
check_expr_or_type(c, &operand, init);
}
if (operand.mode == Addressing_Type) {
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
d->type_expr = d->init_expr;
check_type_decl(c, e, d->type_expr, named_type);
return;
}
check_init_constant(c, e, &operand);
if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_invalid) {
error(e->token, "Invalid declaration type");
}
}
bool are_signatures_similar_enough(Type *a_, Type *b_) {
GB_ASSERT(a_->kind == Type_Proc);
GB_ASSERT(b_->kind == Type_Proc);
TypeProc *a = &a_->Proc;
TypeProc *b = &b_->Proc;
if (a->param_count != b->param_count) {
return false;
}
if (a->result_count != b->result_count) {
return false;
}
for (isize i = 0; i < a->param_count; i++) {
Type *x = base_type(a->params->Tuple.variables[i]->type);
Type *y = base_type(b->params->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (!are_types_identical(x, y)) {
return false;
}
}
for (isize i = 0; i < a->result_count; i++) {
Type *x = base_type(a->results->Tuple.variables[i]->type);
Type *y = base_type(b->results->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (!are_types_identical(x, y)) {
return false;
}
}
return true;
}
void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL);
if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
error_node(d->proc_lit, "Expected a procedure to check");
return;
}
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
e->type = proc_type;
ast_node(pd, ProcLit, d->proc_lit);
check_open_scope(c, pd->type);
check_procedure_type(c, proc_type, pd->type);
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
bool is_require_results = (pd->tags & ProcTag_require_results) != 0;
if (d->scope->is_file && str_eq(e->token.string, str_lit("main"))) {
if (proc_type != NULL) {
TypeProc *pt = &proc_type->Proc;
if (pt->param_count != 0 ||
pt->result_count != 0) {
gbString str = type_to_string(proc_type);
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str);
}
}
}
if (is_inline && is_no_inline) {
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_link_name) {
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
} else if (is_foreign && is_export) {
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
}
if (pd->body != NULL) {
if (is_foreign) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
}
if (proc_type != NULL && is_type_proc(proc_type)) {
TypeProc *tp = &proc_type->Proc;
if (tp->result_count == 0 && is_require_results) {
error_node(pd->type, "`#require_results` is not needed on a procedure with no results");
} else {
tp->require_results = is_require_results;
}
}
if (is_foreign) {
MapEntity *fp = &c->info.foreigns;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
}
AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library;
if (foreign_library == NULL) {
error(e->token, "#foreign procedures must declare which library they are from");
} else if (foreign_library->kind != AstNode_Ident) {
error_node(foreign_library, "#foreign library names must be an identifier");
} else {
String name = foreign_library->Ident.string;
Entity *found = scope_lookup_entity(c->context.scope, name);
if (found == NULL) {
if (str_eq(name, str_lit("_"))) {
error_node(foreign_library, "`_` cannot be used as a value type");
} else {
error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
}
} else if (found->kind != Entity_LibraryName) {
error_node(foreign_library, "`_` cannot be used as a library name");
} else {
// TODO(bill): Extra stuff to do with library names?
e->Procedure.foreign_library = found;
add_entity_use(c, foreign_library, found);
}
}
e->Procedure.is_foreign = true;
e->Procedure.foreign_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error_node(d->proc_lit,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
}
} else {
String name = e->token.string;
if (is_link_name) {
name = pd->link_name;
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreigns;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error_node(d->proc_lit,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
}
}
check_close_scope(c);
}
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->kind == Entity_Variable);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
if (type_expr != NULL) {
e->type = check_type_extra(c, type_expr, NULL);
}
if (init_expr == NULL) {
if (type_expr == NULL) {
e->type = t_invalid;
}
return;
}
if (entities == NULL || entity_count == 1) {
GB_ASSERT(entities == NULL || entities[0] == e);
Operand operand = {0};
check_expr(c, &operand, init_expr);
check_init_variable(c, e, &operand, str_lit("variable declaration"));
}
if (type_expr != NULL) {
for (isize i = 0; i < entity_count; i++) {
entities[i]->type = e->type;
}
}
AstNodeArray inits;
array_init_reserve(&inits, c->allocator, 1);
array_add(&inits, init_expr);
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
}
void check_alias_decl(Checker *c, Entity *e, AstNode *expr, Type *named_type) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->kind == Entity_Alias);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
e->type = t_invalid;
expr = unparen_expr(expr);
if (expr->kind == AstNode_Alias) {
error_node(expr, "#alias of an #alias is not allowed");
return;
}
Operand operand = {0};
check_expr_or_type(c, &operand, expr);
if (operand.mode != Addressing_Type) {
error_node(expr, "#alias declarations only allow types");
return;
}
e->kind = Entity_TypeName;
e->TypeName.is_type_alias = true;
e->type = NULL;
DeclInfo *d = c->context.decl;
d->type_expr = expr;
check_type_decl(c, e, d->type_expr, named_type);
// Operand o = {0};
// Entity *f = NULL;
// if (expr->kind == AstNode_Ident) {
// f = check_ident(c, &o, expr, NULL, NULL, true);
// } else if (expr->kind == AstNode_SelectorExpr) {
// f = check_selector(c, &o, expr, NULL);
// } else {
// check_expr_or_type(c, &o, expr);
// }
// if (o.mode == Addressing_Invalid) {
// return;
// }
// switch (o.mode) {
// case Addressing_Type:
// e->type = o.type;
// // e->kind = Entity_TypeName;
// // e->TypeName.is_type_alias = true;
// e->Alias.kind = EntityAlias_Type;
// e->Alias.original = f;
// break;
// default:
// error_node(expr, "#alias declarations only allow types");
// e->kind = Entity_Invalid;
// e->type = t_invalid;
// break;
// }
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
return;
}
if (d == NULL) {
DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e));
if (found) {
d = *found;
} else {
// TODO(bill): Err here?
e->type = t_invalid;
set_base_type(named_type, t_invalid);
return;
// GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
}
}
CheckerContext prev = c->context;
c->context.scope = d->scope;
c->context.decl = d;
switch (e->kind) {
case Entity_Variable:
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
break;
case Entity_Constant:
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName:
check_type_decl(c, e, d->type_expr, named_type);
break;
case Entity_Alias:
check_alias_decl(c, e, d->init_expr, named_type);
break;
case Entity_Procedure:
check_proc_lit(c, e, d);
break;
}
c->context = prev;
}
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
GB_ASSERT(body->kind == AstNode_BlockStmt);
String proc_name = {0};
if (token.kind == Token_Ident) {
proc_name = token.string;
} else {
// TODO(bill): Better name
proc_name = str_lit("(anonymous-procedure)");
}
CheckerContext old_context = c->context;
c->context.scope = decl->scope;
c->context.decl = decl;
c->context.proc_name = proc_name;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
for (isize i = 0; i < params->variable_count; i++) {
Entity *e = params->variables[i];
GB_ASSERT(e->kind == Entity_Variable);
if (!(e->flags & EntityFlag_Using)) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
break;
}
}
}
} else {
error(e->token, "`using` can only be applied to variables of type struct or raw_union");
break;
}
}
}
push_procedure(c, type);
{
ast_node(bs, BlockStmt, body);
check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
error(bs->close, "Missing return statement at the end of the procedure `%.*s`", LIT(token.string));
} else {
error(bs->close, "Missing return statement at the end of the procedure");
}
}
}
}
pop_procedure(c);
check_scope_usage(c, c->context.scope);
c->context = old_context;
if (decl->parent != NULL) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
for_array(i, decl->deps.entries) {
HashKey key = decl->deps.entries.e[i].key;
Entity *e = cast(Entity *)key.ptr;
map_bool_set(&decl->parent->deps, key, true);
}
}
}
+768
View File
@@ -0,0 +1,768 @@
bool check_is_terminating(AstNode *node);
void check_stmt (Checker *c, AstNode *node, u32 flags);
// NOTE(bill): `content_name` is for debugging and error messages
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
if (operand->mode == Addressing_Builtin) {
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error(operand->expr,
"Cannot assign built-in procedure `%s` in %.*s",
expr_str,
LIT(context_name));
operand->mode = Addressing_Invalid;
gb_string_free(expr_str);
}
if (operand->mode == Addressing_Overload) {
if (e->type == nullptr) {
error(operand->expr, "Cannot determine type from overloaded procedure `%.*s`", LIT(operand->overload_entities[0]->token.string));
} else {
check_assignment(c, operand, e->type, str_lit("variable assignment"));
if (operand->mode != Addressing_Type) {
return operand->type;
}
}
}
if (e->type == nullptr) {
e->type = t_invalid;
}
return nullptr;
}
if (e->type == nullptr) {
// NOTE(bill): Use the type of the operand
Type *t = operand->type;
if (is_type_untyped(t)) {
if (t == t_invalid || is_type_untyped_nil(t)) {
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
e->type = t_invalid;
return nullptr;
}
if (t == t_invalid || is_type_untyped_undef(t)) {
error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
e->type = t_invalid;
return nullptr;
}
t = default_type(t);
}
if (is_type_polymorphic(t)) {
gbString str = type_to_string(t);
defer (gb_string_free(str));
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
e->type = t_invalid;
return nullptr;
} else if (is_type_empty_union(t)) {
gbString str = type_to_string(t);
defer (gb_string_free(str));
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
e->type = t_invalid;
return nullptr;
}
if (is_type_bit_field_value(t)) {
t = default_bit_field_value_type(t);
}
GB_ASSERT(is_type_typed(t));
e->type = t;
}
e->parent_proc_decl = c->context.curr_proc_decl;
check_assignment(c, operand, e->type, context_name);
if (operand->mode == Addressing_Invalid) {
return nullptr;
}
return e->type;
}
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
return;
}
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
defer (gb_temp_arena_memory_end(tmp));
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
Array<Operand> operands = {};
array_init(&operands, c->tmp_allocator, 2*lhs_count);
check_unpack_arguments(c, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands[i].mode == Addressing_Invalid) {
rhs_count--;
}
}
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands[i], context_name);
}
if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
}
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
}
if (operand->mode != Addressing_Constant) {
// TODO(bill): better error
gbString str = expr_to_string(operand->expr);
error(operand->expr, "`%s` is not a constant", str);
gb_string_free(str);
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
}
if (!is_type_constant_type(operand->type)) {
gbString type_str = type_to_string(operand->type);
error(operand->expr, "Invalid constant type: `%s`", type_str);
gb_string_free(type_str);
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
}
if (e->type == nullptr) { // NOTE(bill): type inference
e->type = operand->type;
}
check_assignment(c, operand, e->type, str_lit("constant declaration"));
if (operand->mode == Addressing_Invalid) {
return;
}
e->parent_proc_decl = c->context.curr_proc_decl;
e->Constant.value = operand->value;
}
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
GB_ASSERT(e->type == nullptr);
String name = e->token.string;
Type *named = make_type_named(c->allocator, name, nullptr, e);
named->Named.type_name = e;
if (def != nullptr && def->kind == Type_Named) {
def->Named.base = named;
}
e->type = named;
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
Type *bt = check_type(c, type_expr, named);
named->Named.base = base_type(bt);
if (named->Named.base == t_invalid) {
// gb_printf("check_type_decl: %s\n", type_to_string(named));
}
}
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Constant);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
if (type_expr) {
Type *t = check_type(c, type_expr);
if (!is_type_constant_type(t)) {
gbString str = type_to_string(t);
error(type_expr, "Invalid constant type `%s`", str);
gb_string_free(str);
e->type = t_invalid;
return;
}
e->type = t;
}
Operand operand = {};
if (init != nullptr) {
Entity *entity = nullptr;
if (init->kind == AstNode_Ident) {
entity = check_ident(c, &operand, init, nullptr, e->type, true);
} else if (init->kind == AstNode_SelectorExpr) {
entity = check_selector(c, &operand, init, e->type);
} else {
check_expr_or_type(c, &operand, init, e->type);
}
switch (operand.mode) {
case Addressing_Type: {
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
if (d->type_expr != nullptr) {
error(e->token, "A type declaration cannot have an type parameter");
}
d->type_expr = d->init_expr;
check_type_decl(c, e, d->type_expr, named_type);
return;
} break;
// NOTE(bill): Check to see if the expression it to be aliases
#if 1
case Addressing_Builtin:
if (e->type != nullptr) {
error(type_expr, "A constant alias of a built-in procedure may not have a type initializer");
}
e->kind = Entity_Builtin;
e->Builtin.id = operand.builtin_id;
e->type = t_invalid;
return;
case Addressing_Overload:
e->kind = Entity_Alias;
e->Alias.base = operand.overload_entities[0];
e->type = t_invalid;
return;
#endif
}
#if 1
if (entity != nullptr) {
switch (entity->kind) {
case Entity_Alias:
e->kind = Entity_Alias;
e->type = entity->type;
e->Alias.base = entity->Alias.base;
return;
case Entity_Procedure:
e->kind = Entity_Alias;
e->type = entity->type;
e->Alias.base = entity;
return;
case Entity_ImportName:
e->kind = Entity_ImportName;
e->type = entity->type;
e->ImportName.path = entity->ImportName.path;
e->ImportName.name = entity->ImportName.path;
e->ImportName.scope = entity->ImportName.scope;
e->ImportName.used = false;
return;
case Entity_LibraryName:
e->kind = Entity_LibraryName;
e->type = entity->type;
e->LibraryName.path = entity->LibraryName.path;
e->LibraryName.name = entity->LibraryName.path;
e->LibraryName.used = false;
return;
}
}
#endif
}
if (init != nullptr) {
check_expr_or_type(c, &operand, init, e->type);
}
check_init_constant(c, e, &operand);
if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_invalid) {
gbString str = expr_to_string(init);
error(e->token, "Invalid declaration type `%s`", str);
gb_string_free(str);
}
}
bool are_signatures_similar_enough(Type *a_, Type *b_) {
GB_ASSERT(a_->kind == Type_Proc);
GB_ASSERT(b_->kind == Type_Proc);
TypeProc *a = &a_->Proc;
TypeProc *b = &b_->Proc;
if (a->param_count != b->param_count) {
return false;
}
if (a->result_count != b->result_count) {
return false;
}
for (isize i = 0; i < a->param_count; i++) {
Type *x = core_type(a->params->Tuple.variables[i]->type);
Type *y = core_type(b->params->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (is_type_integer(x) && is_type_integer(y)) {
GB_ASSERT(x->kind == Type_Basic);
GB_ASSERT(y->kind == Type_Basic);
i64 sx = type_size_of(heap_allocator(), x);
i64 sy = type_size_of(heap_allocator(), y);
if (sx == sy) continue;
}
if (!are_types_identical(x, y)) return false;
}
for (isize i = 0; i < a->result_count; i++) {
Type *x = base_type(a->results->Tuple.variables[i]->type);
Type *y = base_type(b->results->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (is_type_integer(x) && is_type_integer(y)) {
GB_ASSERT(x->kind == Type_Basic);
GB_ASSERT(y->kind == Type_Basic);
i64 sx = type_size_of(heap_allocator(), x);
i64 sy = type_size_of(heap_allocator(), y);
if (sx == sy) continue;
}
if (!are_types_identical(x, y)) {
return false;
}
}
return true;
}
void init_entity_foreign_library(Checker *c, Entity *e) {
AstNode *ident = nullptr;
Entity **foreign_library = nullptr;
switch (e->kind) {
case Entity_Procedure:
ident = e->Procedure.foreign_library_ident;
foreign_library = &e->Procedure.foreign_library;
break;
case Entity_Variable:
ident = e->Variable.foreign_library_ident;
foreign_library = &e->Variable.foreign_library;
break;
default:
return;
}
if (ident == nullptr) {
error(e->token, "foreign entiies must declare which library they are from");
} else if (ident->kind != AstNode_Ident) {
error(ident, "foreign library names must be an identifier");
} else {
String name = ident->Ident.token.string;
Entity *found = scope_lookup_entity(c->context.scope, name);
if (found == nullptr) {
if (is_blank_ident(name)) {
error(ident, "`_` cannot be used as a value type");
} else {
error(ident, "Undeclared name: %.*s", LIT(name));
}
} else if (found->kind != Entity_LibraryName) {
error(ident, "`%.*s` cannot be used as a library name", LIT(name));
} else {
// TODO(bill): Extra stuff to do with library names?
*foreign_library = found;
add_entity_use(c, ident, found);
}
}
}
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
error(d->proc_lit, "Expected a procedure to check");
return;
}
Type *proc_type = e->type;
if (d->gen_proc_type != nullptr) {
proc_type = d->gen_proc_type;
} else {
proc_type = make_type_proc(c->allocator, e->scope, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
}
e->type = proc_type;
ast_node(pl, ProcLit, d->proc_lit);
check_open_scope(c, pl->type);
defer (check_close_scope(c));
auto prev_context = c->context;
c->context.allow_polymorphic_types = true;
check_procedure_type(c, proc_type, pl->type);
c->context = prev_context;
TypeProc *pt = &proc_type->Proc;
bool is_foreign = (pl->tags & ProcTag_foreign) != 0;
bool is_link_name = (pl->tags & ProcTag_link_name) != 0;
bool is_export = (pl->tags & ProcTag_export) != 0;
bool is_inline = (pl->tags & ProcTag_inline) != 0;
bool is_no_inline = (pl->tags & ProcTag_no_inline) != 0;
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
if (d->scope->is_file && e->token.string == "main") {
if (pt->param_count != 0 ||
pt->result_count != 0) {
gbString str = type_to_string(proc_type);
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str);
}
if (pt->calling_convention != ProcCC_Odin &&
pt->calling_convention != ProcCC_Contextless) {
error(e->token, "Procedure `main` cannot have a custom calling convention");
}
pt->calling_convention = ProcCC_Contextless;
}
if (is_inline && is_no_inline) {
error(pl->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_export) {
error(pl->type, "A foreign procedure cannot have an `export` tag");
}
if (pt->is_polymorphic) {
if (pl->body == nullptr) {
error(e->token, "Polymorphic procedures must have a body");
}
if (is_foreign) {
error(e->token, "A foreign procedure cannot be a polymorphic");
return;
}
}
if (pl->body != nullptr) {
if (is_foreign) {
error(pl->body, "A foreign procedure cannot have a body");
}
if (proc_type->Proc.c_vararg) {
error(pl->body, "A procedure with a `#c_vararg` field cannot have a body and must be foreign");
}
d->scope = c->context.scope;
GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
if (!pt->is_polymorphic) {
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
}
} else if (!is_foreign) {
error(e->token, "Only a foreign procedure cannot have a body");
}
if (pt->result_count == 0 && is_require_results) {
error(pl->type, "`#require_results` is not needed on a procedure with no results");
} else {
pt->require_results = is_require_results;
}
if (is_foreign) {
String name = e->token.string;
if (pl->link_name.len > 0) {
name = pl->link_name;
}
e->Procedure.is_foreign = true;
e->Procedure.link_name = name;
init_entity_foreign_library(c, e);
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (is_type_proc(this_type) && is_type_proc(other_type)) {
if (!are_signatures_similar_enough(this_type, other_type)) {
error(d->proc_lit,
"Redeclaration of foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else if (!are_types_identical(this_type, other_type)) {
error(d->proc_lit,
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_set(fp, key, e);
}
} else {
String name = e->token.string;
if (is_link_name) {
name = pl->link_name;
}
if (is_link_name || is_export) {
auto *fp = &c->info.foreigns;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error(d->proc_lit,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_set(fp, key, e);
}
}
}
}
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
String context_name = str_lit("variable declaration");
if (type_expr != nullptr) {
e->type = check_type(c, type_expr);
}
if (e->type != nullptr) {
if (is_type_polymorphic(base_type(e->type))) {
gbString str = type_to_string(e->type);
defer (gb_string_free(str));
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
e->type = t_invalid;
} else if (is_type_empty_union(e->type)) {
gbString str = type_to_string(e->type);
defer (gb_string_free(str));
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
e->type = t_invalid;
}
}
if (e->Variable.is_foreign) {
if (init_expr != nullptr) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
init_entity_foreign_library(c, e);
String name = e->token.string;
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_types_identical(this_type, other_type)) {
error(e->token,
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_set(fp, key, e);
}
}
if (init_expr == nullptr) {
if (type_expr == nullptr) {
e->type = t_invalid;
}
return;
}
if (entities == nullptr || entity_count == 1) {
GB_ASSERT(entities == nullptr || entities[0] == e);
Operand operand = {};
check_expr(c, &operand, init_expr);
check_init_variable(c, e, &operand, context_name);
}
if (type_expr != nullptr) {
for (isize i = 0; i < entity_count; i++) {
entities[i]->type = e->type;
}
}
Array<AstNode *> inits;
array_init(&inits, c->allocator, 1);
array_add(&inits, init_expr);
check_init_variables(c, entities, entity_count, inits, context_name);
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != nullptr) {
return;
}
if (d == nullptr) {
d = decl_info_of_entity(&c->info, e);
if (d == nullptr) {
// TODO(bill): Err here?
e->type = t_invalid;
set_base_type(named_type, t_invalid);
return;
// GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
}
}
CheckerContext prev = c->context;
c->context.scope = d->scope;
c->context.decl = d;
e->parent_proc_decl = c->context.curr_proc_decl;
switch (e->kind) {
case Entity_Variable:
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
break;
case Entity_Constant:
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName:
check_type_decl(c, e, d->type_expr, named_type);
break;
case Entity_Procedure:
check_proc_decl(c, e, d);
break;
}
c->context = prev;
}
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
if (body == nullptr) {
return;
}
GB_ASSERT(body->kind == AstNode_BlockStmt);
String proc_name = {};
if (token.kind == Token_Ident) {
proc_name = token.string;
} else {
// TODO(bill): Better name
proc_name = str_lit("(anonymous-procedure)");
}
CheckerContext old_context = c->context;
defer (c->context = old_context);
c->context.scope = decl->scope;
c->context.decl = decl;
c->context.proc_name = proc_name;
c->context.curr_proc_decl = decl;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
for_array(i, params->variables) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (!(e->flags & EntityFlag_Using)) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope;
if (scope == nullptr) {
scope = scope_of_node(&c->info, t->Struct.node);
}
GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != nullptr) {
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
break;
}
}
}
} else {
error(e->token, "`using` can only be applied to variables of type struct");
break;
}
}
}
push_procedure(c, type);
{
ast_node(bs, BlockStmt, body);
check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
error(bs->close, "Missing return statement at the end of the procedure `%.*s`", LIT(token.string));
} else {
error(bs->close, "Missing return statement at the end of the procedure");
}
}
}
}
pop_procedure(c);
check_scope_usage(c, c->context.scope);
if (decl->parent != nullptr) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
for_array(i, decl->deps.entries) {
HashKey key = decl->deps.entries[i].key;
Entity *e = cast(Entity *)key.ptr;
map_set(&decl->parent->deps, key, true);
}
}
}
-6263
View File
File diff suppressed because it is too large Load Diff
+8620
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-2045
View File
File diff suppressed because it is too large Load Diff
+2434
View File
File diff suppressed because it is too large Load Diff
-250
View File
@@ -1,250 +0,0 @@
#if defined(GB_SYSTEM_UNIX)
// Required for intrinsics on GCC
#include <xmmintrin.h>
#endif
#define GB_NO_DEFER
#define GB_IMPLEMENTATION
#include "gb/gb.h"
#include <math.h>
gbAllocator heap_allocator(void) {
return gb_heap_allocator();
}
#include "unicode.c"
#include "string.c"
#include "array.c"
gb_global String global_module_path = {0};
gb_global bool global_module_path_set = false;
gb_global gbScratchMemory scratch_memory = {0};
void init_scratch_memory(isize size) {
void *memory = gb_alloc(heap_allocator(), size);
gb_scratch_memory_init(&scratch_memory, memory, size);
}
gbAllocator scratch_allocator(void) {
return gb_scratch_allocator(&scratch_memory);
}
typedef struct DynamicArenaBlock DynamicArenaBlock;
typedef struct DynamicArena DynamicArena;
struct DynamicArenaBlock {
DynamicArenaBlock *prev;
DynamicArenaBlock *next;
u8 * start;
isize count;
isize capacity;
gbVirtualMemory vm;
};
struct DynamicArena {
DynamicArenaBlock *start_block;
DynamicArenaBlock *current_block;
isize block_size;
};
DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) {
GB_ASSERT(a != NULL);
GB_ASSERT(a->block_size > 0);
gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size);
DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data;
u8 *start = cast(u8 *)gb_align_forward(cast(u8 *)(block + 1), GB_DEFAULT_MEMORY_ALIGNMENT);
u8 *end = cast(u8 *)vm.data + vm.size;
block->vm = vm;
block->start = start;
block->count = 0;
block->capacity = end-start;
if (a->current_block != NULL) {
a->current_block->next = block;
block->prev = a->current_block;
}
a->current_block = block;
return block;
}
void init_dynamic_arena(DynamicArena *a, isize block_size) {
isize size = gb_size_of(DynamicArenaBlock) + block_size;
size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT);
a->block_size = size;
a->start_block = add_dynamic_arena_block(a);
}
void destroy_dynamic_arena(DynamicArena *a) {
DynamicArenaBlock *b = a->current_block;
while (b != NULL) {
gbVirtualMemory vm = b->vm;
b = b->prev;
gb_vm_free(b->vm);
}
}
GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) {
DynamicArena *a = cast(DynamicArena *)allocator_data;
void *ptr = NULL;
switch (type) {
case gbAllocation_Alloc: {
} break;
case gbAllocation_Free: {
} break;
case gbAllocation_Resize: {
} break;
case gbAllocation_FreeAll:
GB_PANIC("free_all is not supported by this allocator");
break;
}
return ptr;
}
gbAllocator dynamic_arena_allocator(DynamicArena *a) {
gbAllocator allocator = {dynamic_arena_allocator_proc, a};
return allocator;
}
i64 next_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
n++;
return n;
}
i64 prev_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n - (n >> 1);
}
i16 f32_to_f16(f32 value) {
union { u32 i; f32 f; } v;
i32 i, s, e, m;
v.f = value;
i = (i32)v.i;
s = (i >> 16) & 0x00008000;
e = ((i >> 23) & 0x000000ff) - (127 - 15);
m = i & 0x007fffff;
if (e <= 0) {
if (e < -10) return cast(i16)s;
m = (m | 0x00800000) >> (1 - e);
if (m & 0x00001000)
m += 0x00002000;
return cast(i16)(s | (m >> 13));
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */
} else {
/* NOTE(bill): NAN */
m >>= 13;
return cast(i16)(s | 0x7c00 | m | (m == 0));
}
} else {
if (m & 0x00001000) {
m += 0x00002000;
if (m & 0x00800000) {
m = 0;
e += 1;
}
}
if (e > 30) {
float volatile f = 1e12f;
int j;
for (j = 0; j < 10; j++) {
f *= f; /* NOTE(bill): Cause overflow */
}
return cast(i16)(s | 0x7c00);
}
return cast(i16)(s | (e << 10) | (m >> 13));
}
}
f64 gb_sqrt(f64 x) {
return sqrt(x);
}
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
// Doubly Linked Lists
#define DLIST_SET(curr_element, next_element) do { \
(curr_element)->next = (next_element); \
(curr_element)->next->prev = (curr_element); \
(curr_element) = (curr_element)->next; \
} while (0)
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
if ((root_element) == NULL) { \
(root_element) = (curr_element) = (next_element); \
} else { \
DLIST_SET(curr_element, next_element); \
} \
} while (0)
////////////////////////////////////////////////////////////////
//
// Generic Data Structures
//
////////////////////////////////////////////////////////////////
typedef Array(i32) Array_i32;
typedef Array(isize) Array_isize;
#define MAP_TYPE String
#define MAP_PROC map_string_
#define MAP_NAME MapString
#include "map.c"
#define MAP_TYPE bool
#define MAP_PROC map_bool_
#define MAP_NAME MapBool
#include "map.c"
#define MAP_TYPE isize
#define MAP_PROC map_isize_
#define MAP_NAME MapIsize
#include "map.c"
+463
View File
@@ -0,0 +1,463 @@
#if defined(GB_SYSTEM_UNIX)
// Required for intrinsics on GCC
#include <xmmintrin.h>
#endif
#define GB_IMPLEMENTATION
#include "gb/gb.h"
#include <wchar.h>
#include <stdio.h>
#include <math.h>
GB_ALLOCATOR_PROC(heap_allocator_proc);
gbAllocator heap_allocator(void) {
gbAllocator a;
a.proc = heap_allocator_proc;
a.data = NULL;
return a;
}
GB_ALLOCATOR_PROC(heap_allocator_proc) {
void *ptr = NULL;
gb_unused(allocator_data);
gb_unused(old_size);
// TODO(bill): Throughly test!
switch (type) {
#if defined(GB_COMPILER_MSVC)
case gbAllocation_Alloc:
ptr = _aligned_malloc(size, alignment);
if (flags & gbAllocatorFlag_ClearToZero)
gb_zero_size(ptr, size);
break;
case gbAllocation_Free:
_aligned_free(old_memory);
break;
case gbAllocation_Resize:
ptr = _aligned_realloc(old_memory, size, alignment);
break;
#elif defined(GB_SYSTEM_LINUX)
// TODO(bill): *nix version that's decent
case gbAllocation_Alloc: {
ptr = aligned_alloc(alignment, size);
// ptr = malloc(size+alignment);
if (flags & gbAllocatorFlag_ClearToZero) {
gb_zero_size(ptr, size);
}
} break;
case gbAllocation_Free: {
free(old_memory);
} break;
case gbAllocation_Resize: {
// ptr = realloc(old_memory, size);
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
} break;
#else
// TODO(bill): *nix version that's decent
case gbAllocation_Alloc: {
posix_memalign(&ptr, alignment, size);
if (flags & gbAllocatorFlag_ClearToZero) {
gb_zero_size(ptr, size);
}
} break;
case gbAllocation_Free: {
free(old_memory);
} break;
case gbAllocation_Resize: {
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
} break;
#endif
case gbAllocation_FreeAll:
break;
}
return ptr;
}
#include "unicode.cpp"
#include "string.cpp"
#include "array.cpp"
#include "integer128.cpp"
#include "murmurhash3.cpp"
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
u128 fnv128a(void const *data, isize len) {
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
u8 const *bytes = cast(u8 const *)data;
for (isize i = 0; i < len; i++) {
h.lo ^= bytes[i];
h = h * o;
}
return h;
}
#include "map.cpp"
gb_global String global_module_path = {0};
gb_global bool global_module_path_set = false;
gb_global gbScratchMemory scratch_memory = {0};
void init_scratch_memory(isize size) {
void *memory = gb_alloc(heap_allocator(), size);
gb_scratch_memory_init(&scratch_memory, memory, size);
}
gbAllocator scratch_allocator(void) {
return gb_scratch_allocator(&scratch_memory);
}
struct Pool {
isize memblock_size;
isize out_of_band_size;
isize alignment;
Array<u8 *> unused_memblock;
Array<u8 *> used_memblock;
Array<u8 *> out_of_band_allocations;
u8 * current_memblock;
u8 * current_pos;
isize bytes_left;
gbAllocator block_allocator;
};
enum {
POOL_BUCKET_SIZE_DEFAULT = 65536,
POOL_OUT_OF_BAND_SIZE_DEFAULT = 6554,
};
void pool_init(Pool *pool,
isize memblock_size = POOL_BUCKET_SIZE_DEFAULT,
isize out_of_band_size = POOL_OUT_OF_BAND_SIZE_DEFAULT,
isize alignment = 8,
gbAllocator block_allocator = heap_allocator(),
gbAllocator array_allocator = heap_allocator()) {
pool->memblock_size = memblock_size;
pool->out_of_band_size = out_of_band_size;
pool->alignment = alignment;
pool->block_allocator = block_allocator;
array_init(&pool->unused_memblock, array_allocator);
array_init(&pool->used_memblock, array_allocator);
array_init(&pool->out_of_band_allocations, array_allocator);
}
void pool_free_all(Pool *p) {
if (p->current_memblock != nullptr) {
array_add(&p->unused_memblock, p->current_memblock);
p->current_memblock = nullptr;
}
for_array(i, p->used_memblock) {
array_add(&p->unused_memblock, p->used_memblock[i]);
}
array_clear(&p->unused_memblock);
for_array(i, p->out_of_band_allocations) {
gb_free(p->block_allocator, p->out_of_band_allocations[i]);
}
array_clear(&p->out_of_band_allocations);
}
void pool_destroy(Pool *p) {
pool_free_all(p);
for_array(i, p->unused_memblock) {
gb_free(p->block_allocator, p->unused_memblock[i]);
}
}
void pool_cycle_new_block(Pool *p) {
GB_ASSERT_MSG(p->block_allocator.proc != nullptr,
"You must call pool_init on a Pool before using it!");
if (p->current_memblock != nullptr) {
array_add(&p->used_memblock, p->current_memblock);
}
u8 *new_block = nullptr;
if (p->unused_memblock.count > 0) {
new_block = array_pop(&p->unused_memblock);
} else {
GB_ASSERT(p->block_allocator.proc != nullptr);
new_block = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, p->alignment);
}
p->bytes_left = p->memblock_size;
p->current_memblock = new_block;
p->current_memblock = new_block;
}
void *pool_get(Pool *p,
isize size, isize alignment = 0) {
if (alignment <= 0) alignment = p->alignment;
isize extra = alignment - (size & alignment);
size += extra;
if (size >= p->out_of_band_size) {
GB_ASSERT(p->block_allocator.proc != nullptr);
u8 *memory = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, alignment);
if (memory != nullptr) {
array_add(&p->out_of_band_allocations, memory);
}
return memory;
}
if (p->bytes_left < size) {
pool_cycle_new_block(p);
if (p->current_memblock != nullptr) {
return nullptr;
}
}
u8 *res = p->current_pos;
p->current_pos += size;
p->bytes_left -= size;
return res;
}
gbAllocator pool_allocator(Pool *pool);
GB_ALLOCATOR_PROC(pool_allocator_procedure) {
Pool *p = cast(Pool *)allocator_data;
void *ptr = nullptr;
switch (type) {
case gbAllocation_Alloc:
return pool_get(p, size, alignment);
case gbAllocation_Free:
// Does nothing
break;
case gbAllocation_FreeAll:
pool_free_all(p);
break;
case gbAllocation_Resize:
return gb_default_resize_align(pool_allocator(p), old_memory, old_size, size, alignment);
}
return ptr;
}
gbAllocator pool_allocator(Pool *pool) {
gbAllocator allocator;
allocator.proc = pool_allocator_procedure;
allocator.data = pool;
return allocator;
}
i32 next_pow2(i32 n) {
if (n <= 0) {
return 0;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
i64 next_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
n++;
return n;
}
i32 prev_pow2(i32 n) {
if (n <= 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n - (n >> 1);
}
i64 prev_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n - (n >> 1);
}
i16 f32_to_f16(f32 value) {
union { u32 i; f32 f; } v;
i32 i, s, e, m;
v.f = value;
i = (i32)v.i;
s = (i >> 16) & 0x00008000;
e = ((i >> 23) & 0x000000ff) - (127 - 15);
m = i & 0x007fffff;
if (e <= 0) {
if (e < -10) return cast(i16)s;
m = (m | 0x00800000) >> (1 - e);
if (m & 0x00001000)
m += 0x00002000;
return cast(i16)(s | (m >> 13));
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */
} else {
/* NOTE(bill): NAN */
m >>= 13;
return cast(i16)(s | 0x7c00 | m | (m == 0));
}
} else {
if (m & 0x00001000) {
m += 0x00002000;
if (m & 0x00800000) {
m = 0;
e += 1;
}
}
if (e > 30) {
float volatile f = 1e12f;
int j;
for (j = 0; j < 10; j++) {
f *= f; /* NOTE(bill): Cause overflow */
}
return cast(i16)(s | 0x7c00);
}
return cast(i16)(s | (e << 10) | (m >> 13));
}
}
f64 gb_sqrt(f64 x) {
return sqrt(x);
}
// Doubly Linked Lists
#define DLIST_SET(curr_element, next_element) do { \
(curr_element)->next = (next_element); \
(curr_element)->next->prev = (curr_element); \
(curr_element) = (curr_element)->next; \
} while (0)
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
if ((root_element) == nullptr) { \
(root_element) = (curr_element) = (next_element); \
} else { \
DLIST_SET(curr_element, next_element); \
} \
} while (0)
#if defined(GB_SYSTEM_WINDOWS)
wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
u32 i, j;
u32 len = cast(u32)string16_len(cmd_line);
i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *);
wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t));
wchar_t *_argv = cast(wchar_t *)((cast(u8 *)argv)+i);
u32 argc = 0;
argv[argc] = _argv;
bool in_quote = false;
bool in_text = false;
bool in_space = true;
i = 0;
j = 0;
for (;;) {
wchar_t a = cmd_line[i];
if (a == 0) {
break;
}
if (in_quote) {
if (a == '\"') {
in_quote = false;
} else {
_argv[j++] = a;
}
} else {
switch (a) {
case '\"':
in_quote = true;
in_text = true;
if (in_space) argv[argc++] = _argv+j;
in_space = false;
break;
case ' ':
case '\t':
case '\n':
case '\r':
if (in_text) _argv[j++] = '\0';
in_text = false;
in_space = true;
break;
default:
in_text = true;
if (in_space) argv[argc++] = _argv+j;
_argv[j++] = a;
in_space = false;
break;
}
}
i++;
}
_argv[j] = '\0';
argv[argc] = nullptr;
if (_argc) *_argc = argc;
return argv;
}
#endif
+130
View File
@@ -0,0 +1,130 @@
// Generates Documentation
gbString expr_to_string(AstNode *expression);
String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
isize len = 0;
for_array(i, g.list) {
String comment = g.list[i].string;
len += comment.len;
len += 1; // for \n
}
if (len == 0) {
return make_string(nullptr, 0);
}
u8 *text = gb_alloc_array(a, u8, len+1);
len = 0;
for_array(i, g.list) {
String comment = g.list[i].string;
if (comment[1] == '/') {
comment.text += 2;
comment.len -= 2;
} else if (comment[1] == '*') {
comment.text += 2;
comment.len -= 4;
}
comment = string_trim_whitespace(comment);
gb_memmove(text+len, comment.text, comment.len);
len += comment.len;
text[len++] = '\n';
}
return make_string(text, len);
}
#if 0
void print_type_spec(AstNode *spec) {
ast_node(ts, TypeSpec, spec);
GB_ASSERT(ts->name->kind == AstNode_Ident);
String name = ts->name->Ident.string;
if (name.len == 0) {
return;
}
if (name[0] == '_') {
return;
}
gb_printf("type %.*s\n", LIT(name));
}
void print_proc_decl(AstNodeProcDecl *pd) {
GB_ASSERT(pd->name->kind == AstNode_Ident);
String name = pd->name->Ident.string;
if (name.len == 0) {
return;
}
if (name[0] == '_') {
return;
}
String docs = alloc_comment_group_string(heap_allocator(), pd->docs);
defer (gb_free(heap_allocator(), docs.text));
if (docs.len > 0) {
gb_file_write(&gb__std_files[gbFileStandard_Output], docs.text, docs.len);
} else {
return;
}
ast_node(proc_type, ProcType, pd->type);
gbString params = expr_to_string(proc_type->params);
defer (gb_string_free(params));
gb_printf("proc %.*s(%s)", LIT(name), params);
if (proc_type->results != nullptr) {
ast_node(fl, FieldList, proc_type->results);
isize count = fl->list.count;
if (count > 0) {
gbString results = expr_to_string(proc_type->results);
defer (gb_string_free(results));
gb_printf(" -> ");
if (count != 1) {
gb_printf("(");
}
gb_printf("%s", results);
if (count != 1) {
gb_printf(")");
}
}
}
gb_printf("\n\n");
}
#endif
void print_declaration(AstNode *decl) {
switch (decl->kind) {
case_ast_node(gd, GenDecl, decl);
for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs[spec_index];
switch(gd->token.kind) {
case Token_import:
case Token_import_load:
break;
case Token_foreign_library:
case Token_foreign_system_library:
break;
}
}
case_end;
// case_ast_node(pd, ProcDecl, decl);
// print_proc_decl(pd);
// case_end;
case_ast_node(fb, ForeignBlockDecl, decl);
// TODO(bill)
case_end;
}
}
void generate_documentation(Parser *parser) {
for_array(file_index, parser->files) {
AstFile *file = &parser->files[file_index];
Tokenizer *tokenizer = &file->tokenizer;
String fullpath = tokenizer->fullpath;
gb_printf("%.*s\n", LIT(fullpath));
for_array(decl_index, file->decls) {
AstNode *decl = file->decls[decl_index];
print_declaration(decl);
}
}
}
+66 -49
View File
@@ -1,6 +1,7 @@
typedef struct Scope Scope; struct Scope;
typedef struct Checker Checker; struct Checker;
typedef struct Type Type; struct Type;
struct DeclInfo;
// typedef enum BuiltinProcId BuiltinProcId; // typedef enum BuiltinProcId BuiltinProcId;
@@ -11,18 +12,18 @@ typedef struct Type Type;
ENTITY_KIND(TypeName) \ ENTITY_KIND(TypeName) \
ENTITY_KIND(Procedure) \ ENTITY_KIND(Procedure) \
ENTITY_KIND(Builtin) \ ENTITY_KIND(Builtin) \
ENTITY_KIND(Alias) \
ENTITY_KIND(ImportName) \ ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \ ENTITY_KIND(LibraryName) \
ENTITY_KIND(Alias) \
ENTITY_KIND(Nil) \ ENTITY_KIND(Nil) \
ENTITY_KIND(Label) ENTITY_KIND(Label)
typedef enum EntityKind { enum EntityKind {
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k), #define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
ENTITY_KINDS ENTITY_KINDS
#undef ENTITY_KIND #undef ENTITY_KIND
Entity_Count, Entity_Count,
} EntityKind; };
String const entity_strings[] = { String const entity_strings[] = {
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1}, #define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
@@ -30,35 +31,39 @@ String const entity_strings[] = {
#undef ENTITY_KIND #undef ENTITY_KIND
}; };
typedef enum EntityFlag { enum EntityFlag {
EntityFlag_Visited = 1<<0, EntityFlag_Visited = 1<<0,
EntityFlag_Used = 1<<1, EntityFlag_Used = 1<<1,
EntityFlag_Using = 1<<2, EntityFlag_Using = 1<<2,
EntityFlag_Field = 1<<3, EntityFlag_Field = 1<<3,
EntityFlag_Param = 1<<4, EntityFlag_Param = 1<<4,
EntityFlag_VectorElem = 1<<5, EntityFlag_VectorElem = 1<<5,
EntityFlag_Ellipsis = 1<<6, EntityFlag_Ellipsis = 1<<6,
EntityFlag_NoAlias = 1<<7, EntityFlag_NoAlias = 1<<7,
EntityFlag_TypeField = 1<<8, EntityFlag_TypeField = 1<<8,
EntityFlag_Value = 1<<9, EntityFlag_Value = 1<<9,
} EntityFlag; EntityFlag_Sret = 1<<10,
EntityFlag_BitFieldValue = 1<<11,
EntityFlag_CVarArg = 1<<20,
};
// Zero value means the overloading process is not yet done // Zero value means the overloading process is not yet done
typedef enum OverloadKind { enum OverloadKind {
Overload_Unknown, Overload_Unknown,
Overload_No, Overload_No,
Overload_Yes, Overload_Yes,
} OverloadKind; };
typedef enum EntityAliasKind { enum EntityAliasKind {
EntityAlias_Invalid, EntityAlias_Invalid,
EntityAlias_Type, EntityAlias_Type,
EntityAlias_Entity, EntityAlias_Entity,
} EntityAliasKind; };
// An Entity is a named "thing" in the language // An Entity is a named "thing" in the language
typedef struct Entity Entity;
struct Entity { struct Entity {
EntityKind kind; EntityKind kind;
u64 id; u64 id;
@@ -66,7 +71,8 @@ struct Entity {
Token token; Token token;
Scope * scope; Scope * scope;
Type * type; Type * type;
AstNode * identifier; // Can be NULL AstNode * identifier; // Can be nullptr
DeclInfo * parent_proc_decl; // nullptr if in file/global scope
// TODO(bill): Cleanup how `using` works for entities // TODO(bill): Cleanup how `using` works for entities
Entity * using_parent; Entity * using_parent;
@@ -77,25 +83,37 @@ struct Entity {
ExactValue value; ExactValue value;
} Constant; } Constant;
struct { struct {
i32 field_index; i32 field_index;
i32 field_src_index; i32 field_src_index;
bool is_immutable; ExactValue default_value;
bool is_thread_local; bool default_is_nil;
bool default_is_undef;
bool default_is_location;
bool is_immutable;
bool is_thread_local;
bool is_foreign;
Entity * foreign_library;
AstNode * foreign_library_ident;
String link_name;
} Variable; } Variable;
struct { struct {
bool is_type_alias; bool is_type_alias;
Type *type_parameter_specialization;
} TypeName; } TypeName;
struct { struct {
bool is_foreign; OverloadKind overload_kind;
String foreign_name;
Entity * foreign_library;
String link_name; String link_name;
u64 tags; u64 tags;
OverloadKind overload_kind; bool is_foreign;
Entity * foreign_library;
AstNode * foreign_library_ident;
} Procedure; } Procedure;
struct { struct {
i32 id; i32 id;
} Builtin; } Builtin;
struct {
Entity *base;
} Alias;
struct { struct {
String path; String path;
String name; String name;
@@ -107,10 +125,6 @@ struct Entity {
String name; String name;
bool used; bool used;
} LibraryName; } LibraryName;
struct {
EntityAliasKind kind;
Entity * original;
} Alias;
i32 Nil; i32 Nil;
struct { struct {
String name; String name;
@@ -119,7 +133,7 @@ struct Entity {
}; };
}; };
gb_global Entity *e_context = NULL; gb_global Entity *e_context = nullptr;
bool is_entity_kind_exported(EntityKind kind) { bool is_entity_kind_exported(EntityKind kind) {
switch (kind) { switch (kind) {
@@ -134,7 +148,7 @@ bool is_entity_kind_exported(EntityKind kind) {
bool is_entity_exported(Entity *e) { bool is_entity_exported(Entity *e) {
// TODO(bill): Determine the actual exportation rules for imports of entities // TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != NULL); GB_ASSERT(e != nullptr);
if (!is_entity_kind_exported(e->kind)) { if (!is_entity_kind_exported(e->kind)) {
return false; return false;
} }
@@ -143,7 +157,7 @@ bool is_entity_exported(Entity *e) {
if (name.len == 0) { if (name.len == 0) {
return false; return false;
} }
return name.text[0] != '_'; return name[0] != '_';
} }
gb_global u64 global_entity_id = 0; gb_global u64 global_entity_id = 0;
@@ -165,10 +179,11 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
} }
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) { Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
GB_ASSERT(parent != NULL); GB_ASSERT(parent != nullptr);
token.pos = parent->token.pos; token.pos = parent->token.pos;
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type); Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
entity->using_parent = parent; entity->using_parent = parent;
entity->parent_proc_decl = parent->parent_proc_decl;
entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Using;
return entity; return entity;
} }
@@ -223,6 +238,12 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
return entity; return entity;
} }
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) {
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
entity->Alias.base = base;
return entity;
}
Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type, Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
String path, String name, Scope *import_scope) { String path, String name, Scope *import_scope) {
Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type); Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
@@ -240,17 +261,13 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
return entity; return entity;
} }
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type,
EntityAliasKind kind, Entity *original) {
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
entity->Alias.kind = kind;
entity->Alias.original = original;
return entity;
}
Entity *make_entity_nil(gbAllocator a, String name, Type *type) { Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
Token token = make_token_ident(name); Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type); Entity *entity = alloc_entity(a, Entity_Nil, nullptr, token, type);
return entity; return entity;
} }
@@ -265,6 +282,6 @@ Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) { Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_"); token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false); return make_entity_variable(a, scope, token, nullptr, false);
} }
+130 -262
View File
@@ -3,17 +3,16 @@
// TODO(bill): Big numbers // TODO(bill): Big numbers
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!! // IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
typedef struct AstNode AstNode; struct AstNode;
struct HashKey;
struct Type;
bool are_types_identical(Type *x, Type *y);
typedef struct Complex128 { struct Complex128 {
f64 real, imag; f64 real, imag;
} Complex128; };
typedef struct Quaternion256 { enum ExactValueKind {
f64 real, imag, jmag, kmag;
} Quaternion256;
typedef enum ExactValueKind {
ExactValue_Invalid, ExactValue_Invalid,
ExactValue_Bool, ExactValue_Bool,
@@ -21,26 +20,28 @@ typedef enum ExactValueKind {
ExactValue_Integer, ExactValue_Integer,
ExactValue_Float, ExactValue_Float,
ExactValue_Complex, ExactValue_Complex,
ExactValue_Quaternion,
ExactValue_Pointer, ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Type,
ExactValue_Count, ExactValue_Count,
} ExactValueKind; };
typedef struct ExactValue { struct ExactValue {
ExactValueKind kind; ExactValueKind kind;
union { union {
bool value_bool; bool value_bool;
String value_string; String value_string;
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer i128 value_integer; // NOTE(bill): This must be an integer and not a pointer
f64 value_float; f64 value_float;
i64 value_pointer; i64 value_pointer;
Complex128 value_complex; Complex128 value_complex;
Quaternion256 value_quaternion;
AstNode * value_compound; AstNode * value_compound;
Type * value_type;
}; };
} ExactValue; };
gb_global ExactValue const empty_exact_value = {};
HashKey hash_exact_value(ExactValue v) { HashKey hash_exact_value(ExactValue v) {
return hashing_proc(&v, gb_size_of(ExactValue)); return hashing_proc(&v, gb_size_of(ExactValue));
@@ -66,11 +67,22 @@ ExactValue exact_value_string(String string) {
return result; return result;
} }
ExactValue exact_value_integer(i64 i) { ExactValue exact_value_i64(i64 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = i128_from_i64(i);
return result;
}
ExactValue exact_value_i128(i128 i) {
ExactValue result = {ExactValue_Integer}; ExactValue result = {ExactValue_Integer};
result.value_integer = i; result.value_integer = i;
return result; return result;
} }
ExactValue exact_value_u128(u128 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = u128_to_i128(i);
return result;
}
ExactValue exact_value_float(f64 f) { ExactValue exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float}; ExactValue result = {ExactValue_Float};
@@ -85,61 +97,21 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
return result; return result;
} }
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion.real = real;
result.value_quaternion.imag = imag;
result.value_quaternion.jmag = jmag;
result.value_quaternion.kmag = kmag;
return result;
}
ExactValue exact_value_pointer(i64 ptr) { ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer}; ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr; result.value_pointer = ptr;
return result; return result;
} }
ExactValue exact_value_type(Type *type) {
ExactValue result = {ExactValue_Type};
result.value_type = type;
return result;
}
ExactValue exact_value_integer_from_string(String string) { ExactValue exact_value_integer_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them return exact_value_u128(u128_from_string(string));
i32 base = 10;
bool has_prefix = false;
if (string.len > 2 && string.text[0] == '0') {
switch (string.text[1]) {
case 'b': base = 2; has_prefix = true; break;
case 'o': base = 8; has_prefix = true; break;
case 'd': base = 10; has_prefix = true; break;
case 'z': base = 12; has_prefix = true; break;
case 'x': base = 16; has_prefix = true; break;
}
}
u8 *text = string.text;
isize len = string.len;
if (has_prefix) {
text += 2;
len -= 2;
}
i64 result = 0;
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
i64 v = 0;
v = digit_value(r);
if (v >= base) {
break;
}
result *= base;
result += v;
}
return exact_value_integer(result);
} }
f64 float_from_string(String string) { f64 float_from_string(String string) {
@@ -155,6 +127,39 @@ f64 float_from_string(String string) {
i++; i++;
} }
#if 0
if (len-i > 2 &&
str[i] == '0' &&
str[i+1] == 'h') {
i += 2;
u8 *text = string.text;
isize len = string.len;
if (has_prefix) {
text += 2;
len -= 2;
}
u64 base = 16;
u64 result = {0};
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
u64 v = bit128__digit_value(r);
if (v >= base) {
break;
}
result *= base;
result += v;
}
return *cast(f64 *)&result;
}
#endif
f64 value = 0.0; f64 value = 0.0;
for (; i < len; i++) { for (; i < len; i++) {
Rune r = cast(Rune)str[i]; Rune r = cast(Rune)str[i];
@@ -232,21 +237,19 @@ ExactValue exact_value_from_basic_literal(Token token) {
case Token_Float: return exact_value_float_from_string(token.string); case Token_Float: return exact_value_float_from_string(token.string);
case Token_Imag: { case Token_Imag: {
String str = token.string; String str = token.string;
Rune last_rune = cast(Rune)str.text[str.len-1]; Rune last_rune = cast(Rune)str[str.len-1];
str.len--; // Ignore the `i|j|k` str.len--; // Ignore the `i|j|k`
f64 imag = float_from_string(str); f64 imag = float_from_string(str);
switch (last_rune) { if (last_rune == 'i') {
case 'i': return exact_value_complex(0, imag); return exact_value_complex(0, imag);
case 'j': return exact_value_quaternion(0, 0, imag, 0);
case 'k': return exact_value_quaternion(0, 0, 0, imag);
} }
} }
case Token_Rune: { case Token_Rune: {
Rune r = GB_RUNE_INVALID; Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r); gb_utf8_decode(token.string.text, token.string.len, &r);
// gb_printf("%.*s rune: %d\n", LIT(token.string), r); // gb_printf("%.*s rune: %d\n", LIT(token.string), r);
return exact_value_integer(r); return exact_value_i64(r);
} }
default: default:
GB_PANIC("Invalid token for basic literal"); GB_PANIC("Invalid token for basic literal");
@@ -262,15 +265,15 @@ ExactValue exact_value_to_integer(ExactValue v) {
case ExactValue_Integer: case ExactValue_Integer:
return v; return v;
case ExactValue_Float: { case ExactValue_Float: {
i64 i = cast(i64)v.value_float; i128 i = i128_from_f64(v.value_float);
f64 f = cast(f64)i; f64 f = i128_to_f64(i);
if (f == v.value_float) { if (f == v.value_float) {
return exact_value_integer(i); return exact_value_i128(i);
} }
} break; } break;
case ExactValue_Pointer: case ExactValue_Pointer:
return exact_value_integer(cast(i64)cast(intptr)v.value_pointer); return exact_value_i64(cast(i64)cast(intptr)v.value_pointer);
} }
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
@@ -279,7 +282,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
ExactValue exact_value_to_float(ExactValue v) { ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) { switch (v.kind) {
case ExactValue_Integer: case ExactValue_Integer:
return exact_value_float(cast(i64)v.value_integer); return exact_value_float(i128_to_f64(v.value_integer));
case ExactValue_Float: case ExactValue_Float:
return v; return v;
} }
@@ -290,7 +293,7 @@ ExactValue exact_value_to_float(ExactValue v) {
ExactValue exact_value_to_complex(ExactValue v) { ExactValue exact_value_to_complex(ExactValue v) {
switch (v.kind) { switch (v.kind) {
case ExactValue_Integer: case ExactValue_Integer:
return exact_value_complex(cast(i64)v.value_integer, 0); return exact_value_complex(i128_to_f64(v.value_integer), 0);
case ExactValue_Float: case ExactValue_Float:
return exact_value_complex(v.value_float, 0); return exact_value_complex(v.value_float, 0);
case ExactValue_Complex: case ExactValue_Complex:
@@ -301,22 +304,6 @@ ExactValue exact_value_to_complex(ExactValue v) {
} }
ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(cast(i64)v.value_integer, 0, 0, 0);
case ExactValue_Float:
return exact_value_quaternion(v.value_float, 0, 0, 0);
case ExactValue_Complex:
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
case ExactValue_Quaternion:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_real(ExactValue v) { ExactValue exact_value_real(ExactValue v) {
switch (v.kind) { switch (v.kind) {
case ExactValue_Integer: case ExactValue_Integer:
@@ -324,8 +311,6 @@ ExactValue exact_value_real(ExactValue v) {
return v; return v;
case ExactValue_Complex: case ExactValue_Complex:
return exact_value_float(v.value_complex.real); return exact_value_float(v.value_complex.real);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.real);
} }
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
@@ -335,42 +320,14 @@ ExactValue exact_value_imag(ExactValue v) {
switch (v.kind) { switch (v.kind) {
case ExactValue_Integer: case ExactValue_Integer:
case ExactValue_Float: case ExactValue_Float:
return exact_value_integer(0); return exact_value_i64(0);
case ExactValue_Complex: case ExactValue_Complex:
return exact_value_float(v.value_complex.imag); return exact_value_float(v.value_complex.imag);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.imag);
} }
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
} }
ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_integer(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.jmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_integer(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.kmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_imag(ExactValue v) { ExactValue exact_value_make_imag(ExactValue v) {
switch (v.kind) { switch (v.kind) {
case ExactValue_Integer: case ExactValue_Integer:
@@ -383,31 +340,6 @@ ExactValue exact_value_make_imag(ExactValue v) {
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
} }
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_jmag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_kmag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) { ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) {
@@ -418,7 +350,6 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Integer: case ExactValue_Integer:
case ExactValue_Float: case ExactValue_Float:
case ExactValue_Complex: case ExactValue_Complex:
case ExactValue_Quaternion:
return v; return v;
} }
} break; } break;
@@ -442,18 +373,11 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
f64 imag = v.value_complex.imag; f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag); return exact_value_complex(-real, -imag);
} }
case ExactValue_Quaternion: {
f64 real = v.value_quaternion.real;
f64 imag = v.value_quaternion.imag;
f64 jmag = v.value_quaternion.jmag;
f64 kmag = v.value_quaternion.kmag;
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
}
} }
} break; } break;
case Token_Xor: { case Token_Xor: {
i64 i = 0; i128 i = I128_ZERO;
switch (v.kind) { switch (v.kind) {
case ExactValue_Invalid: case ExactValue_Invalid:
return v; return v;
@@ -467,11 +391,11 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
// NOTE(bill): unsigned integers will be negative and will need to be // NOTE(bill): unsigned integers will be negative and will need to be
// limited to the types precision // limited to the types precision
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored // IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
if (0 < precision && precision < 64) { if (0 < precision && precision < 128) {
i &= ~((~0ll)<<precision); i = i & ~(I128_NEG_ONE << precision);
} }
return exact_value_integer(i); return exact_value_i128(i);
} break; } break;
case Token_Not: { case Token_Not: {
@@ -486,7 +410,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
failure: failure:
GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op])); GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op]));
ExactValue error_value = {0}; ExactValue error_value = {};
return error_value; return error_value;
} }
@@ -504,10 +428,8 @@ i32 exact_value_order(ExactValue v) {
return 3; return 3;
case ExactValue_Complex: case ExactValue_Complex:
return 4; return 4;
case ExactValue_Quaternion:
return 5;
case ExactValue_Pointer: case ExactValue_Pointer:
return 6; return 5;
default: default:
GB_PANIC("How'd you get here? Invalid Value.kind"); GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -529,7 +451,6 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool: case ExactValue_Bool:
case ExactValue_String: case ExactValue_String:
case ExactValue_Complex: case ExactValue_Complex:
case ExactValue_Quaternion:
return; return;
case ExactValue_Integer: case ExactValue_Integer:
@@ -538,13 +459,10 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
return; return;
case ExactValue_Float: case ExactValue_Float:
// TODO(bill): Is this good enough? // TODO(bill): Is this good enough?
*x = exact_value_float(cast(f64)x->value_integer); *x = exact_value_float(i128_to_f64(x->value_integer));
return; return;
case ExactValue_Complex: case ExactValue_Complex:
*x = exact_value_complex(cast(f64)x->value_integer, 0); *x = exact_value_complex(i128_to_f64(x->value_integer), 0);
return;
case ExactValue_Quaternion:
*x = exact_value_quaternion(cast(f64)x->value_integer, 0, 0, 0);
return; return;
} }
break; break;
@@ -556,9 +474,6 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex: case ExactValue_Complex:
*x = exact_value_to_complex(*x); *x = exact_value_to_complex(*x);
return; return;
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
} }
break; break;
} }
@@ -585,26 +500,27 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
break; break;
case ExactValue_Integer: { case ExactValue_Integer: {
i64 a = x.value_integer; i128 a = x.value_integer;
i64 b = y.value_integer; i128 b = y.value_integer;
i64 c = 0; i128 c = I128_ZERO;
switch (op) { switch (op) {
case Token_Add: c = a + b; break; case Token_Add: c = a + b; break;
case Token_Sub: c = a - b; break; case Token_Sub: c = a - b; break;
case Token_Mul: c = a * b; break; case Token_Mul: c = a * b; break;
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b)); case Token_Quo: return exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b)));
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break; case Token_Mod: c = a % b; break;
case Token_And: c = a & b; break; case Token_ModMod: c = ((a % b) + b) % b; break;
case Token_Or: c = a | b; break; case Token_And: c = a & b; break;
case Token_Xor: c = a ^ b; break; case Token_Or: c = a | b; break;
case Token_AndNot: c = a&(~b); break; case Token_Xor: c = a ^ b; break;
case Token_Shl: c = a << b; break; case Token_AndNot: c = i128_and_not(a, b); break;
case Token_Shr: c = a >> b; break; case Token_Shl: c = a << cast(u32)i128_to_u64(b); break;
case Token_Shr: c = a >> cast(u32)i128_to_u64(b); break;
default: goto error; default: goto error;
} }
return exact_value_integer(c); return exact_value_i128(c);
} break; } break;
case ExactValue_Float: { case ExactValue_Float: {
@@ -650,59 +566,22 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
return exact_value_complex(real, imag); return exact_value_complex(real, imag);
} break; } break;
case ExactValue_Quaternion: { case ExactValue_String: {
y = exact_value_to_quaternion(y); if (op != Token_Add) goto error;
f64 a = x.value_quaternion.real;
f64 b = x.value_quaternion.imag;
f64 c = x.value_quaternion.jmag;
f64 d = x.value_quaternion.kmag;
f64 e = x.value_quaternion.real; // NOTE(bill): How do you minimize this over allocation?
f64 f = x.value_quaternion.imag; String sx = x.value_string;
f64 g = x.value_quaternion.jmag; String sy = y.value_string;
f64 h = x.value_quaternion.kmag; isize len = sx.len+sy.len;
u8 *data = gb_alloc_array(heap_allocator(), u8, len);
f64 real = 0; gb_memmove(data, sx.text, sx.len);
f64 imag = 0; gb_memmove(data+sx.len, sy.text, sy.len);
f64 jmag = 0; return exact_value_string(make_string(data, len));
f64 kmag = 0;
switch (op) {
case Token_Add:
real = a + e;
imag = b + f;
jmag = c + g;
kmag = d + h;
break;
case Token_Sub:
real = a - e;
imag = b - f;
jmag = c - g;
kmag = d - h;
break;
case Token_Mul:
real = a*f + b*e + c*h - d*g;
imag = a*g - b*h + c*e + d*f;
jmag = a*h + b*g - c*f + d*e;
kmag = a*e - b*f - c*g - d*h;
break;
case Token_Quo: {
f64 s = e*e + f*f + g*g + h*h;
real = (+a*e + b*f + c*g + d*h)/s;
imag = (-a*f + b*e - c*h + d*h)/s;
jmag = (-a*g + b*h + c*e - d*f)/s;
kmag = (-a*h - b*g + c*f + d*e)/s;
} break;
default: goto error;
}
return exact_value_quaternion(real, imag, jmag, kmag);
} break; } break;
} }
error: error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels... return empty_exact_value;
ExactValue error_value = {0};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value;
} }
gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); } gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }
@@ -731,8 +610,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
break; break;
case ExactValue_Integer: { case ExactValue_Integer: {
i64 a = x.value_integer; i128 a = x.value_integer;
i64 b = y.value_integer; i128 b = y.value_integer;
switch (op) { switch (op) {
case Token_CmpEq: return a == b; case Token_CmpEq: return a == b;
case Token_NotEq: return a != b; case Token_NotEq: return a != b;
@@ -767,37 +646,26 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
} }
} break; } break;
case ExactValue_Quaternion: {
f64 a = x.value_quaternion.real;
f64 b = x.value_quaternion.imag;
f64 c = x.value_quaternion.jmag;
f64 d = x.value_quaternion.kmag;
f64 e = y.value_quaternion.real;
f64 f = y.value_quaternion.imag;
f64 g = y.value_quaternion.jmag;
f64 h = y.value_quaternion.kmag;
switch (op) {
case Token_CmpEq: return cmp_f64(a, e) == 0 && cmp_f64(b, f) == 0 && cmp_f64(c, g) == 0 && cmp_f64(d, h) == 0;
case Token_NotEq: return cmp_f64(a, e) != 0 || cmp_f64(b, f) != 0 || cmp_f64(c, g) != 0 || cmp_f64(d, h) != 0;
}
} break;
case ExactValue_String: { case ExactValue_String: {
String a = x.value_string; String a = x.value_string;
String b = y.value_string; String b = y.value_string;
isize len = gb_min(a.len, b.len);
// TODO(bill): gb_memcompare is used because the strings are UTF-8 // TODO(bill): gb_memcompare is used because the strings are UTF-8
switch (op) { switch (op) {
case Token_CmpEq: return gb_memcompare(a.text, b.text, len) == 0; case Token_CmpEq: return a == b;
case Token_NotEq: return gb_memcompare(a.text, b.text, len) != 0; case Token_NotEq: return a != b;
case Token_Lt: return gb_memcompare(a.text, b.text, len) < 0; case Token_Lt: return a < b;
case Token_LtEq: return gb_memcompare(a.text, b.text, len) <= 0; case Token_LtEq: return a <= b;
case Token_Gt: return gb_memcompare(a.text, b.text, len) > 0; case Token_Gt: return a > b;
case Token_GtEq: return gb_memcompare(a.text, b.text, len) >= 0; case Token_GtEq: return a >= b;
} }
} break; } break;
case ExactValue_Type:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_type, y.value_type);
case Token_NotEq: return !are_types_identical(x.value_type, y.value_type);
}
break;
} }
GB_PANIC("Invalid comparison"); GB_PANIC("Invalid comparison");
+121 -75
View File
@@ -1,4 +1,4 @@
/* gb.h - v0.28 - Ginger Bill's C Helper Library - public domain /* gb.h - v0.31 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk - no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff This is a single header file with a bunch of useful stuff
@@ -58,6 +58,9 @@ TODOS
- More date & time functions - More date & time functions
VERSION HISTORY VERSION HISTORY
0.31 - Add gb_file_remove
0.30 - Changes to gbThread (and gbMutex on Windows)
0.29 - Add extras for gbString
0.28 - Handle UCS2 correctly in Win32 part 0.28 - Handle UCS2 correctly in Win32 part
0.27 - OSX fixes and Linux gbAffinity 0.27 - OSX fixes and Linux gbAffinity
0.26d - Minor changes to how gbFile works 0.26d - Minor changes to how gbFile works
@@ -164,11 +167,11 @@ extern "C" {
#endif #endif
#ifndef GB_EDIAN_ORDER #ifndef GB_ENDIAN_ORDER
#define GB_EDIAN_ORDER #define GB_ENDIAN_ORDER
// TODO(bill): Is the a good way or is it better to test for certain compilers and macros? // TODO(bill): Is the a good way or is it better to test for certain compilers and macros?
#define GB_IS_BIG_EDIAN (!*(u8*)&(u16){1}) #define GB_IS_BIG_ENDIAN (!*(u8*)&(u16){1})
#define GB_IS_LITTLE_EDIAN (!GB_IS_BIG_EDIAN) #define GB_IS_LITTLE_ENDIAN (!GB_IS_BIG_ENDIAN)
#endif #endif
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
@@ -927,12 +930,12 @@ GB_DEF void gb_semaphore_wait (gbSemaphore *s);
// Mutex // Mutex
// TODO(bill): Should this be replaced with a CRITICAL_SECTION on win32 or is the better?
typedef struct gbMutex { typedef struct gbMutex {
gbSemaphore semaphore; #if defined(GB_SYSTEM_WINDOWS)
gbAtomic32 counter; CRITICAL_SECTION win32_critical_section;
gbAtomic32 owner; #else
i32 recursion; pthread_mutex_t pthread_mutex;
#endif
} gbMutex; } gbMutex;
GB_DEF void gb_mutex_init (gbMutex *m); GB_DEF void gb_mutex_init (gbMutex *m);
@@ -956,7 +959,7 @@ gb_mutex_init(&m);
#define GB_THREAD_PROC(name) void name(void *data) #define GB_THREAD_PROC(name) isize name(struct gbThread *thread)
typedef GB_THREAD_PROC(gbThreadProc); typedef GB_THREAD_PROC(gbThreadProc);
typedef struct gbThread { typedef struct gbThread {
@@ -967,7 +970,9 @@ typedef struct gbThread {
#endif #endif
gbThreadProc *proc; gbThreadProc *proc;
void * data; void * user_data;
isize user_index;
isize return_value;
gbSemaphore semaphore; gbSemaphore semaphore;
isize stack_size; isize stack_size;
@@ -975,7 +980,7 @@ typedef struct gbThread {
} gbThread; } gbThread;
GB_DEF void gb_thread_init (gbThread *t); GB_DEF void gb_thread_init (gbThread *t);
GB_DEF void gb_thread_destory (gbThread *t); GB_DEF void gb_thread_destroy (gbThread *t);
GB_DEF void gb_thread_start (gbThread *t, gbThreadProc *proc, void *data); GB_DEF void gb_thread_start (gbThread *t, gbThreadProc *proc, void *data);
GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size); GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
GB_DEF void gb_thread_join (gbThread *t); GB_DEF void gb_thread_join (gbThread *t);
@@ -1521,6 +1526,8 @@ GB_DEF void gb_string_clear (gbString str);
GB_DEF gbString gb_string_append (gbString str, gbString const other); GB_DEF gbString gb_string_append (gbString str, gbString const other);
GB_DEF gbString gb_string_append_length (gbString str, void const *other, isize num_bytes); GB_DEF gbString gb_string_append_length (gbString str, void const *other, isize num_bytes);
GB_DEF gbString gb_string_appendc (gbString str, char const *other); GB_DEF gbString gb_string_appendc (gbString str, char const *other);
GB_DEF gbString gb_string_append_rune (gbString str, Rune r);
GB_DEF gbString gb_string_append_fmt (gbString str, char const *fmt, ...);
GB_DEF gbString gb_string_set (gbString str, char const *cstr); GB_DEF gbString gb_string_set (gbString str, char const *cstr);
GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len); GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len);
GB_DEF isize gb_string_allocation_size(gbString const str); GB_DEF isize gb_string_allocation_size(gbString const str);
@@ -2044,6 +2051,7 @@ GB_DEF b32 gb_file_exists (char const *filepath);
GB_DEF gbFileTime gb_file_last_write_time(char const *filepath); GB_DEF gbFileTime gb_file_last_write_time(char const *filepath);
GB_DEF b32 gb_file_copy (char const *existing_filename, char const *new_filename, b32 fail_if_exists); GB_DEF b32 gb_file_copy (char const *existing_filename, char const *new_filename, b32 fail_if_exists);
GB_DEF b32 gb_file_move (char const *existing_filename, char const *new_filename); GB_DEF b32 gb_file_move (char const *existing_filename, char const *new_filename);
GB_DEF b32 gb_file_remove (char const *filename);
#ifndef GB_PATH_SEPARATOR #ifndef GB_PATH_SEPARATOR
@@ -3602,7 +3610,7 @@ extern "C" {
#endif #endif
void gb_assert_handler(char const *condition, char const *file, i32 line, char const *msg, ...) { void gb_assert_handler(char const *condition, char const *file, i32 line, char const *msg, ...) {
gb_printf_err("%s:%d: Assert Failure: ", file, line); gb_printf_err("%s(%d): Assert Failure: ", file, line);
if (condition) if (condition)
gb_printf_err( "`%s` ", condition); gb_printf_err( "`%s` ", condition);
if (msg) { if (msg) {
@@ -4590,59 +4598,44 @@ gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
#error #error
#endif #endif
// NOTE(bill): THIS IS FUCKING AWESOME THAT THIS "MUTEX" IS FAST AND RECURSIVE TOO!
// NOTE(bill): WHO THE FUCK NEEDS A NORMAL MUTEX NOW?!?!?!?!
gb_inline void gb_mutex_init(gbMutex *m) { gb_inline void gb_mutex_init(gbMutex *m) {
gb_atomic32_store(&m->counter, 0); #if defined(GB_SYSTEM_WINDOWS)
gb_atomic32_store(&m->owner, gb_thread_current_id()); InitializeCriticalSection(&m->win32_critical_section);
gb_semaphore_init(&m->semaphore); #else
m->recursion = 0; pthread_mutex_init(&m->pthread_mutex, NULL);
#endif
} }
gb_inline void gb_mutex_destroy(gbMutex *m) { gb_semaphore_destroy(&m->semaphore); } gb_inline void gb_mutex_destroy(gbMutex *m) {
#if defined(GB_SYSTEM_WINDOWS)
DeleteCriticalSection(&m->win32_critical_section);
#else
pthread_mutex_destroy(&m->pthread_mutex);
#endif
}
gb_inline void gb_mutex_lock(gbMutex *m) { gb_inline void gb_mutex_lock(gbMutex *m) {
i32 thread_id = cast(i32)gb_thread_current_id(); #if defined(GB_SYSTEM_WINDOWS)
if (gb_atomic32_fetch_add(&m->counter, 1) > 0) { EnterCriticalSection(&m->win32_critical_section);
if (thread_id != gb_atomic32_load(&m->owner)) #else
gb_semaphore_wait(&m->semaphore); pthread_mutex_lock(&m->pthread_mutex);
} #endif
gb_atomic32_store(&m->owner, thread_id);
m->recursion++;
} }
gb_inline b32 gb_mutex_try_lock(gbMutex *m) { gb_inline b32 gb_mutex_try_lock(gbMutex *m) {
i32 thread_id = cast(i32)gb_thread_current_id(); #if defined(GB_SYSTEM_WINDOWS)
if (gb_atomic32_load(&m->owner) == thread_id) { return TryEnterCriticalSection(&m->win32_critical_section) != 0;
gb_atomic32_fetch_add(&m->counter, 1); #else
} else { return pthread_mutex_trylock(&m->pthread_mutex) == 0;
i32 expected = 0; #endif
if (gb_atomic32_load(&m->counter) != 0)
return false;
if (!gb_atomic32_compare_exchange(&m->counter, expected, 1))
return false;
gb_atomic32_store(&m->owner, thread_id);
}
m->recursion++;
return true;
} }
gb_inline void gb_mutex_unlock(gbMutex *m) { gb_inline void gb_mutex_unlock(gbMutex *m) {
i32 recursion; #if defined(GB_SYSTEM_WINDOWS)
i32 thread_id = cast(i32)gb_thread_current_id(); LeaveCriticalSection(&m->win32_critical_section);
#else
GB_ASSERT(thread_id == gb_atomic32_load(&m->owner)); pthread_mutex_unlock(&m->pthread_mutex);
#endif
recursion = --m->recursion;
if (recursion == 0)
gb_atomic32_store(&m->owner, thread_id);
if (gb_atomic32_fetch_add(&m->counter, -1) > 1) {
if (recursion == 0)
gb_semaphore_release(&m->semaphore);
}
} }
@@ -4661,7 +4654,7 @@ void gb_thread_init(gbThread *t) {
gb_semaphore_init(&t->semaphore); gb_semaphore_init(&t->semaphore);
} }
void gb_thread_destory(gbThread *t) { void gb_thread_destroy(gbThread *t) {
if (t->is_running) gb_thread_join(t); if (t->is_running) gb_thread_join(t);
gb_semaphore_destroy(&t->semaphore); gb_semaphore_destroy(&t->semaphore);
} }
@@ -4669,22 +4662,32 @@ void gb_thread_destory(gbThread *t) {
gb_inline void gb__thread_run(gbThread *t) { gb_inline void gb__thread_run(gbThread *t) {
gb_semaphore_release(&t->semaphore); gb_semaphore_release(&t->semaphore);
t->proc(t->data); t->return_value = t->proc(t);
} }
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
gb_inline DWORD __stdcall gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return 0; } gb_inline DWORD __stdcall gb__thread_proc(void *arg) {
gbThread *t = cast(gbThread *)arg;
gb__thread_run(t);
t->is_running = false;
return 0;
}
#else #else
gb_inline void * gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return NULL; } gb_inline void * gb__thread_proc(void *arg) {
gbThread *t = cast(gbThread *)arg;
gb__thread_run(t);
t->is_running = false;
return NULL;
}
#endif #endif
gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data) { gb_thread_start_with_stack(t, proc, data, 0); } gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *user_data) { gb_thread_start_with_stack(t, proc, user_data, 0); }
gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size) { gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *user_data, isize stack_size) {
GB_ASSERT(!t->is_running); GB_ASSERT(!t->is_running);
GB_ASSERT(proc != NULL); GB_ASSERT(proc != NULL);
t->proc = proc; t->proc = proc;
t->data = data; t->user_data = user_data;
t->stack_size = stack_size; t->stack_size = stack_size;
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
@@ -4695,8 +4698,9 @@ gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void
pthread_attr_t attr; pthread_attr_t attr;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stack_size != 0) if (stack_size != 0) {
pthread_attr_setstacksize(&attr, stack_size); pthread_attr_setstacksize(&attr, stack_size);
}
pthread_create(&t->posix_handle, &attr, gb__thread_proc, t); pthread_create(&t->posix_handle, &attr, gb__thread_proc, t);
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
} }
@@ -5398,7 +5402,8 @@ gb_inline gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena) {
} }
gb_inline void gb_temp_arena_memory_end(gbTempArenaMemory tmp) { gb_inline void gb_temp_arena_memory_end(gbTempArenaMemory tmp) {
GB_ASSERT(tmp.arena->total_allocated >= tmp.original_count); GB_ASSERT_MSG(tmp.arena->total_allocated >= tmp.original_count,
"%td >= %td", tmp.arena->total_allocated, tmp.original_count);
GB_ASSERT(tmp.arena->temp_count > 0); GB_ASSERT(tmp.arena->temp_count > 0);
tmp.arena->total_allocated = tmp.original_count; tmp.arena->total_allocated = tmp.original_count;
tmp.arena->temp_count--; tmp.arena->temp_count--;
@@ -6384,20 +6389,23 @@ gb_global char const gb__num_to_char_table[] =
gb_inline void gb_i64_to_str(i64 value, char *string, i32 base) { gb_inline void gb_i64_to_str(i64 value, char *string, i32 base) {
char *buf = string; char *buf = string;
b32 negative = false; b32 negative = false;
u64 v;
if (value < 0) { if (value < 0) {
negative = true; negative = true;
value = -value; value = -value;
} }
if (value) { v = cast(u64)value;
while (value > 0) { if (v != 0) {
*buf++ = gb__num_to_char_table[value % base]; while (v > 0) {
value /= base; *buf++ = gb__num_to_char_table[v % base];
v /= base;
} }
} else { } else {
*buf++ = '0'; *buf++ = '0';
} }
if (negative) if (negative) {
*buf++ = '-'; *buf++ = '-';
}
*buf = '\0'; *buf = '\0';
gb_strrev(string); gb_strrev(string);
} }
@@ -6570,6 +6578,26 @@ gb_inline gbString gb_string_appendc(gbString str, char const *other) {
return gb_string_append_length(str, other, gb_strlen(other)); return gb_string_append_length(str, other, gb_strlen(other));
} }
gbString gb_string_append_rune(gbString str, Rune r) {
if (r >= 0) {
u8 buf[8] = {0};
isize len = gb_utf8_encode_rune(buf, r);
return gb_string_append_length(str, buf, len);
}
return str;
}
gbString gb_string_append_fmt(gbString str, char const *fmt, ...) {
isize res;
char buf[4096] = {0};
va_list va;
va_start(va, fmt);
res = gb_snprintf_va(str, gb_count_of(buf)-1, fmt, va);
va_end(va);
return gb_string_append_length(str, buf, res);
}
gbString gb_string_set(gbString str, char const *cstr) { gbString gb_string_set(gbString str, char const *cstr) {
isize len = gb_strlen(cstr); isize len = gb_strlen(cstr);
@@ -7400,13 +7428,13 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) {
if (w_len_) *w_len_ = w_len; if (w_len_) *w_len_ = w_len;
return NULL; return NULL;
} }
w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, NULL, 0); w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int)len, NULL, 0);
if (w_len == 0) { if (w_len == 0) {
if (w_len_) *w_len_ = w_len; if (w_len_) *w_len_ = w_len;
return NULL; return NULL;
} }
w_text = gb_alloc_array(a, wchar_t, w_len+1); w_text = gb_alloc_array(a, wchar_t, w_len+1);
w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, w_text, w_len); w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int)len, w_text, cast(int)w_len);
if (w_len1 == 0) { if (w_len1 == 0) {
gb_free(a, w_text); gb_free(a, w_text);
if (w_len_) *w_len_ = 0; if (w_len_) *w_len_ = 0;
@@ -7905,6 +7933,19 @@ gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filena
return result; return result;
} }
b32 gb_file_remove(char const *filename) {
wchar_t *w_filename = NULL;
gbAllocator a = gb_heap_allocator();
b32 result = false;
w_filename = gb__alloc_utf8_to_ucs2(a, filename, NULL);
if (w_filename == NULL) {
return false;
}
result = DeleteFileW(w_filename);
gb_free(a, w_filename);
return result;
}
#else #else
@@ -7950,6 +7991,11 @@ gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filena
return false; return false;
} }
b32 gb_file_remove(char const *filename) {
return remove(filename) == 0;
}
#endif #endif
@@ -8054,17 +8100,17 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
return NULL; return NULL;
} }
w_fullpath = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1); w_fullpath = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1);
GetFullPathNameW(w_path, w_len, w_fullpath, NULL); GetFullPathNameW(w_path, cast(int)w_len, w_fullpath, NULL);
w_fullpath[w_len] = 0; w_fullpath[w_len] = 0;
gb_free(gb_heap_allocator(), w_path); gb_free(gb_heap_allocator(), w_path);
new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, NULL, 0, NULL, NULL); new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int)w_len, NULL, 0, NULL, NULL);
if (new_len == 0) { if (new_len == 0) {
gb_free(gb_heap_allocator(), w_fullpath); gb_free(gb_heap_allocator(), w_fullpath);
return NULL; return NULL;
} }
new_path = gb_alloc_array(a, char, new_len+1); new_path = gb_alloc_array(a, char, new_len+1);
new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, new_path, new_len, NULL, NULL); new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int)w_len, new_path, cast(int)new_len, NULL, NULL);
if (new_len1 == 0) { if (new_len1 == 0) {
gb_free(gb_heap_allocator(), w_fullpath); gb_free(gb_heap_allocator(), w_fullpath);
gb_free(a, new_path); gb_free(a, new_path);
+726
View File
@@ -0,0 +1,726 @@
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
#define MSVC_AMD64_INTRINSICS
#include <intrin.h>
#pragma intrinsic(_mul128)
#endif
#define BIT128_U64_HIGHBIT 0x8000000000000000ull
#define BIT128_U64_BITS62 0x7fffffffffffffffull
#define BIT128_U64_ALLBITS 0xffffffffffffffffull
typedef struct u128 { u64 lo; u64 hi; } u128;
typedef struct i128 { u64 lo; i64 hi; } i128;
static u128 const U128_ZERO = {0, 0};
static u128 const U128_ONE = {1, 0};
static i128 const I128_ZERO = {0, 0};
static i128 const I128_ONE = {1, 0};
static u128 const U128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS};
static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, cast(i64)BIT128_U64_ALLBITS};
u128 u128_lo_hi (u64 lo, u64 hi);
u128 u128_from_u32 (u32 u);
u128 u128_from_u64 (u64 u);
u128 u128_from_i64 (i64 u);
u128 u128_from_f32 (f32 f);
u128 u128_from_f64 (f64 f);
u128 u128_from_string(String string);
i128 i128_lo_hi (u64 lo, i64 hi);
i128 i128_from_u32 (u32 u);
i128 i128_from_u64 (u64 u);
i128 i128_from_i64 (i64 u);
i128 i128_from_f32 (f32 f);
i128 i128_from_f64 (f64 f);
i128 i128_from_string(String string);
u64 u128_to_u64(u128 a);
i64 u128_to_i64(u128 a);
f64 u128_to_f64(u128 a);
i128 u128_to_i128(u128 a);
u64 i128_to_u64(i128 a);
i64 i128_to_i64(i128 a);
f64 i128_to_f64(i128 a);
u128 i128_to_u128(i128 a);
String u128_to_string(u128 a, char *buf, isize len);
String i128_to_string(i128 a, char *buf, isize len);
i32 u128_cmp (u128 a, u128 b);
bool u128_eq (u128 a, u128 b);
bool u128_ne (u128 a, u128 b);
bool u128_lt (u128 a, u128 b);
bool u128_gt (u128 a, u128 b);
bool u128_le (u128 a, u128 b);
bool u128_ge (u128 a, u128 b);
u128 u128_add (u128 a, u128 b);
u128 u128_not (u128 a);
u128 u128_neg (u128 a);
u128 u128_sub (u128 a, u128 b);
u128 u128_and (u128 a, u128 b);
u128 u128_or (u128 a, u128 b);
u128 u128_xor (u128 a, u128 b);
u128 u128_and_not(u128 a, u128 b);
u128 u128_shl (u128 a, u32 n);
u128 u128_shr (u128 a, u32 n);
u128 u128_mul (u128 a, u128 b);
void u128_divide (u128 num, u128 den, u128 *quo, u128 *rem);
u128 u128_quo (u128 a, u128 b);
u128 u128_mod (u128 a, u128 b);
i128 i128_abs (i128 a);
i32 i128_cmp (i128 a, i128 b);
bool i128_eq (i128 a, i128 b);
bool i128_ne (i128 a, i128 b);
bool i128_lt (i128 a, i128 b);
bool i128_gt (i128 a, i128 b);
bool i128_le (i128 a, i128 b);
bool i128_ge (i128 a, i128 b);
i128 i128_add (i128 a, i128 b);
i128 i128_not (i128 a);
i128 i128_neg (i128 a);
i128 i128_sub (i128 a, i128 b);
i128 i128_and (i128 a, i128 b);
i128 i128_or (i128 a, i128 b);
i128 i128_xor (i128 a, i128 b);
i128 i128_and_not(i128 a, i128 b);
i128 i128_shl (i128 a, u32 n);
i128 i128_shr (i128 a, u32 n);
i128 i128_mul (i128 a, i128 b);
void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem);
i128 i128_quo (i128 a, i128 b);
i128 i128_mod (i128 a, i128 b);
bool operator==(u128 a, u128 b) { return u128_eq(a, b); }
bool operator!=(u128 a, u128 b) { return u128_ne(a, b); }
bool operator< (u128 a, u128 b) { return u128_lt(a, b); }
bool operator> (u128 a, u128 b) { return u128_gt(a, b); }
bool operator<=(u128 a, u128 b) { return u128_le(a, b); }
bool operator>=(u128 a, u128 b) { return u128_ge(a, b); }
u128 operator+(u128 a, u128 b) { return u128_add(a, b); }
u128 operator-(u128 a, u128 b) { return u128_sub(a, b); }
u128 operator*(u128 a, u128 b) { return u128_mul(a, b); }
u128 operator/(u128 a, u128 b) { return u128_quo(a, b); }
u128 operator%(u128 a, u128 b) { return u128_mod(a, b); }
u128 operator&(u128 a, u128 b) { return u128_and(a, b); }
u128 operator|(u128 a, u128 b) { return u128_or (a, b); }
u128 operator^(u128 a, u128 b) { return u128_xor(a, b); }
u128 operator~(u128 a) { return u128_not(a); }
u128 operator+(u128 a) { return a; }
u128 operator-(u128 a) { return u128_neg(a); }
u128 operator<<(u128 a, u32 b) { return u128_shl(a, b); }
u128 operator>>(u128 a, u32 b) { return u128_shr(a, b); }
bool operator==(i128 a, i128 b) { return i128_eq(a, b); }
bool operator!=(i128 a, i128 b) { return i128_ne(a, b); }
bool operator< (i128 a, i128 b) { return i128_lt(a, b); }
bool operator> (i128 a, i128 b) { return i128_gt(a, b); }
bool operator<=(i128 a, i128 b) { return i128_le(a, b); }
bool operator>=(i128 a, i128 b) { return i128_ge(a, b); }
i128 operator+(i128 a, i128 b) { return i128_add(a, b); }
i128 operator-(i128 a, i128 b) { return i128_sub(a, b); }
i128 operator*(i128 a, i128 b) { return i128_mul(a, b); }
i128 operator/(i128 a, i128 b) { return i128_quo(a, b); }
i128 operator%(i128 a, i128 b) { return i128_mod(a, b); }
i128 operator&(i128 a, i128 b) { return i128_and(a, b); }
i128 operator|(i128 a, i128 b) { return i128_or (a, b); }
i128 operator^(i128 a, i128 b) { return i128_xor(a, b); }
i128 operator~(i128 a) { return i128_not(a); }
i128 operator+(i128 a) { return a; }
i128 operator-(i128 a) { return i128_neg(a); }
i128 operator<<(i128 a, u32 b) { return i128_shl(a, b); }
i128 operator>>(i128 a, u32 b) { return i128_shr(a, b); }
////////////////////////////////////////////////////////////////
u64 bit128__digit_value(Rune r) {
if ('0' <= r && r <= '9') {
return r - '0';
} else if ('a' <= r && r <= 'f') {
return r - 'a' + 10;
} else if ('A' <= r && r <= 'F') {
return r - 'A' + 10;
}
return 16; // NOTE(bill): Larger than highest possible
}
u128 u128_lo_hi(u64 lo, u64 hi) {
u128 r = {};
r.lo = lo;
r.hi = hi;
return r;
}
u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); }
u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); }
u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
u128 u128_from_f32(f32 f) { return u128_lo_hi(cast(u64)f, 0); }
u128 u128_from_f64(f64 f) { return u128_lo_hi(cast(u64)f, 0); }
u128 u128_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
u64 base = 10;
bool has_prefix = false;
if (string.len > 2 && string[0] == '0') {
switch (string[1]) {
case 'b': base = 2; has_prefix = true; break;
case 'o': base = 8; has_prefix = true; break;
case 'd': base = 10; has_prefix = true; break;
case 'z': base = 12; has_prefix = true; break;
case 'x': base = 16; has_prefix = true; break;
}
}
u8 *text = string.text;
isize len = string.len;
if (has_prefix) {
text += 2;
len -= 2;
}
u128 base_ = u128_from_u64(base);
u128 result = {0};
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
u64 v = bit128__digit_value(r);
if (v >= base) {
break;
}
result = u128_mul(result, base_);
result = u128_add(result, u128_from_u64(v));
}
return result;
}
i128 i128_lo_hi(u64 lo, i64 hi) {
i128 i;
i.lo = lo;
i.hi = hi;
return i;
}
i128 i128_from_u32(u32 u) { return i128_lo_hi(cast(u64)u, 0); }
i128 i128_from_u64(u64 u) { return i128_lo_hi(cast(u64)u, 0); }
i128 i128_from_i64(i64 u) { return i128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
i128 i128_from_f32(f32 f) { return i128_lo_hi(cast(u64)f, 0); }
i128 i128_from_f64(f64 f) { return i128_lo_hi(cast(u64)f, 0); }
i128 i128_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
u64 base = 10;
bool has_prefix = false;
if (string.len > 2 && string[0] == '0') {
switch (string[1]) {
case 'b': base = 2; has_prefix = true; break;
case 'o': base = 8; has_prefix = true; break;
case 'd': base = 10; has_prefix = true; break;
case 'z': base = 12; has_prefix = true; break;
case 'x': base = 16; has_prefix = true; break;
}
}
u8 *text = string.text;
isize len = string.len;
if (has_prefix) {
text += 2;
len -= 2;
}
i128 base_ = i128_from_u64(base);
i128 result = {0};
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
u64 v = bit128__digit_value(r);
if (v >= base) {
break;
}
result = i128_mul(result, base_);
result = i128_add(result, i128_from_u64(v));
}
return result;
}
u64 u128_to_u64(u128 a) {
return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT);
}
i64 u128_to_i64(u128 a) {
return a.lo;
}
f64 u128_to_f64(u128 a) {
if (a.hi >= 0) {
return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo;
}
i64 h = cast(i64)a.hi;
u64 l = a.lo;
h = ~h;
l = ~l;
l += 1;
if (l == 0) {
h += 1;
}
return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l);
}
i128 u128_to_i128(u128 a) {
return *cast(i128 *)&a;
}
u64 i128_to_u64(i128 a) {
return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT);
}
i64 i128_to_i64(i128 a) {
return cast(i64)a.lo;
}
f64 i128_to_f64(i128 a) {
if (a.hi >= 0) {
return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo;
}
i64 h = a.hi;
u64 l = a.lo;
h = ~h;
l = ~l;
l += 1;
if (l == 0) {
h += 1;
}
return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l);
}
u128 i128_to_u128(i128 a) {
return *cast(u128 *)&a;
}
String u128_to_string(u128 v, char *out_buf, isize out_buf_len) {
char buf[200] = {0};
isize i = gb_size_of(buf);
u128 b = u128_from_u64(10);;
while (u128_ge(v, b)) {
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
v = u128_quo(v, b);
}
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
gb_memcopy(out_buf, &buf[i], len);
return make_string(cast(u8 *)out_buf, len);
}
String i128_to_string(i128 a, char *out_buf, isize out_buf_len) {
char buf[200] = {0};
isize i = gb_size_of(buf);
bool negative = false;
if (i128_lt(a, I128_ZERO)) {
negative = true;
a = i128_neg(a);
}
u128 v = *cast(u128 *)&a;
u128 b = u128_from_u64(10);;
while (u128_ge(v, b)) {
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
v = u128_quo(v, b);
}
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
if (negative) {
buf[--i] = '-';
}
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
gb_memcopy(out_buf, &buf[i], len);
return make_string(cast(u8 *)out_buf, len);
}
////////////////////////////////////////////////////////////////
i32 u128_cmp(u128 a, u128 b) {
if (a.hi == b.hi && b.lo == b.lo) {
return 0;
}
if (a.hi == b.hi) {
return a.lo < b.lo ? -1 : +1;
}
return a.hi < b.hi ? -1 : +1;
}
bool u128_eq(u128 a, u128 b) { return a.hi == b.hi && a.lo == b.lo; }
bool u128_ne(u128 a, u128 b) { return !u128_eq(a, b); }
bool u128_lt(u128 a, u128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; }
bool u128_gt(u128 a, u128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; }
bool u128_le(u128 a, u128 b) { return !u128_gt(a, b); }
bool u128_ge(u128 a, u128 b) { return !u128_lt(a, b); }
u128 u128_add(u128 a, u128 b) {
u128 old_a = a;
a.lo += b.lo;
a.hi += b.hi;
if (a.lo < old_a.lo) {
a.hi += 1;
}
return a;
}
u128 u128_not(u128 a) { return u128_lo_hi(~a.lo, ~a.hi); }
u128 u128_neg(u128 a) {
return u128_add(u128_not(a), u128_from_u64(1));
}
u128 u128_sub(u128 a, u128 b) {
return u128_add(a, u128_neg(b));
}
u128 u128_and(u128 a, u128 b) { return u128_lo_hi(a.lo&b.lo, a.hi&b.hi); }
u128 u128_or (u128 a, u128 b) { return u128_lo_hi(a.lo|b.lo, a.hi|b.hi); }
u128 u128_xor(u128 a, u128 b) { return u128_lo_hi(a.lo^b.lo, a.hi^b.hi); }
u128 u128_and_not(u128 a, u128 b) { return u128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); }
u128 u128_shl(u128 a, u32 n) {
if (n >= 128) {
return u128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.hi = __shiftleft128(a.lo, a.hi, n);
a.lo = a.lo << n;
return a;
#else
if (n >= 64) {
n -= 64;
a.hi = a.lo;
a.lo = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS >> n);
a.hi <<= n;
a.hi |= (a.lo&mask) >> (64 - n);
a.lo <<= n;
}
return a;
#endif
}
u128 u128_shr(u128 a, u32 n) {
if (n >= 128) {
return u128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.lo = __shiftright128(a.lo, a.hi, n);
a.hi = a.hi >> n;
return a;
#else
if (n >= 64) {
n -= 64;
a.lo = a.hi;
a.hi = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS << n);
a.lo >>= n;
a.lo |= (a.hi&mask) << (64 - n);
a.hi >>= n;
}
return a;
#endif
}
u128 u128_mul(u128 a, u128 b) {
if (a.lo == 0 && a.hi == 0) {
return u128_from_u64(0);
} else if (b.lo == 0 && b.hi == 0) {
return u128_from_u64(0);
}
if (u128_eq(a, U128_ONE)) {
return b;
}
if (u128_eq(b, U128_ONE)) {
return a;
}
#if defined(MSVC_AMD64_INTRINSICS)
if (a.hi == 0 && b.hi == 0) {
a.lo = _umul128(a.lo, b.lo, &a.hi);
return a;
}
#endif
u128 res = {0};
u128 t = b;
for (u32 i = 0; i < 128; i++) {
if ((t.lo&1) != 0) {
res = u128_add(res, u128_shl(a, i));
}
t = u128_shr(t, 1);
}
return res;
}
bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; }
void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
if (u128_eq(den, U128_ZERO)) {
if (quo) *quo = u128_from_u64(num.lo/den.lo);
if (rem) *rem = U128_ZERO;
} else {
u128 n = num;
u128 d = den;
u128 x = U128_ONE;
u128 r = U128_ZERO;
while (u128_ge(n, d) && !u128_hibit(&d)) {
x = u128_shl(x, 1);
d = u128_shl(d, 1);
}
while (u128_ne(x, U128_ZERO)) {
if (u128_ge(n, d)) {
n = u128_sub(n, d);
r = u128_or(r, x);
}
x = u128_shr(x, 1);
d = u128_shr(d, 1);
}
if (quo) *quo = r;
if (rem) *rem = n;
}
}
u128 u128_quo(u128 a, u128 b) {
if (a.hi == 0 && b.hi == 0) {
return u128_from_u64(a.lo/b.lo);
}
u128 res = {0};
u128_divide(a, b, &res, nullptr);
return res;
}
u128 u128_mod(u128 a, u128 b) {
if (a.hi == 0 && b.hi == 0) {
return u128_from_u64(a.lo%b.lo);
}
u128 res = {0};
u128_divide(a, b, nullptr, &res);
return res;
}
////////////////////////////////////////////////////////////////
i128 i128_abs(i128 a) {
if ((a.hi&BIT128_U64_HIGHBIT) != 0) {
return i128_neg(a);
}
return a;
}
i32 i128_cmp(i128 a, i128 b) {
if (a.hi == b.hi && b.lo == b.lo) {
return 0;
}
if (a.hi == b.hi) {
return a.lo < b.lo ? -1 : +1;
}
return a.hi < b.hi ? -1 : +1;
}
bool i128_eq(i128 a, i128 b) { return a.hi == b.hi && a.lo == b.lo; }
bool i128_ne(i128 a, i128 b) { return !i128_eq(a, b); }
bool i128_lt(i128 a, i128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; }
bool i128_gt(i128 a, i128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; }
bool i128_le(i128 a, i128 b) { return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi; }
bool i128_ge(i128 a, i128 b) { return a.hi == b.hi ? a.lo >= b.lo : a.hi >= b.hi; }
i128 i128_add(i128 a, i128 b) {
i128 old_a = a;
a.lo += b.lo;
a.hi += b.hi;
if (a.lo < old_a.lo) {
a.hi += 1;
}
return a;
}
i128 i128_not(i128 a) { return i128_lo_hi(~a.lo, ~a.hi); }
i128 i128_neg(i128 a) {
return i128_add(i128_not(a), i128_from_u64(1));
}
i128 i128_sub(i128 a, i128 b) {
return i128_add(a, i128_neg(b));
}
i128 i128_and(i128 a, i128 b) { return i128_lo_hi(a.lo&b.lo, a.hi&b.hi); }
i128 i128_or (i128 a, i128 b) { return i128_lo_hi(a.lo|b.lo, a.hi|b.hi); }
i128 i128_xor(i128 a, i128 b) { return i128_lo_hi(a.lo^b.lo, a.hi^b.hi); }
i128 i128_and_not(i128 a, i128 b) { return i128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); }
i128 i128_shl(i128 a, u32 n) {
if (n >= 128) {
return i128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.hi = __shiftleft128(a.lo, a.hi, n);
a.lo = a.lo << n;
return a;
#else
if (n >= 64) {
n -= 64;
a.hi = a.lo;
a.lo = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS >> n);
a.hi <<= n;
a.hi |= (a.lo&mask) >> (64 - n);
a.lo <<= n;
}
return a;
#endif
}
i128 i128_shr(i128 a, u32 n) {
if (n >= 128) {
return i128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.lo = __shiftright128(a.lo, a.hi, n);
a.hi = a.hi >> n;
return a;
#else
if (n >= 64) {
n -= 64;
a.lo = a.hi;
a.hi = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS << n);
a.lo >>= n;
a.lo |= (a.hi&mask) << (64 - n);
a.hi >>= n;
}
return a;
#endif
}
i128 i128_mul(i128 a, i128 b) {
if (a.lo == 0 && a.hi == 0) {
return i128_from_u64(0);
} else if (b.lo == 0 && b.hi == 0) {
return i128_from_u64(0);
}
if (i128_eq(a, I128_ONE)) {
return b;
}
if (i128_eq(b, I128_ONE)) {
return a;
}
#if defined(MSVC_AMD64_INTRINSICS)
if (a.hi == 0 && b.hi == 0) {
a.lo = _mul128(a.lo, b.lo, &a.hi);
return a;
}
#endif
i128 res = {0};
i128 t = b;
for (u32 i = 0; i < 128; i++) {
if ((t.lo&1) != 0) {
res = i128_add(res, i128_shl(a, i));
}
t = i128_shr(t, 1);
}
return res;
}
void i128_divide(i128 a, i128 b, i128 *quo, i128 *rem) {
// TODO(bill): Which one is correct?!
#if 1
i128 s = i128_shr(b, 127);
b = i128_sub(i128_xor(b, s), s);
s = i128_shr(a, 127);
b = i128_sub(i128_xor(a, s), s);
u128 n, r = {0};
u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &n, &r);
i128 ni = *cast(i128 *)&n;
i128 ri = *cast(i128 *)&r;
if (quo) *quo = i128_sub(i128_xor(ni, s), s);
if (rem) *rem = i128_sub(i128_xor(ri, s), s);
#else
if (i128_eq(b, I128_ZERO)) {
if (quo) *quo = i128_from_u64(a.lo/b.lo);
if (rem) *rem = I128_ZERO;
} else {
i128 n = a;
i128 d = b;
i128 x = I128_ONE;
i128 r = I128_ZERO;
while (i128_ge(n, d) && ((i128_shr(d, 128-1).lo&1) == 0)) {
x = i128_shl(x, 1);
d = i128_shl(d, 1);
}
while (i128_ne(x, I128_ZERO)) {
if (i128_ge(n, d)) {
n = i128_sub(n, d);
r = i128_or(r, x);
}
x = i128_shr(x, 1);
d = i128_shr(d, 1);
}
if (quo) *quo = r;
if (rem) *rem = n;
}
#endif
}
i128 i128_quo(i128 a, i128 b) {
i128 res = {0};
i128_divide(a, b, &res, nullptr);
return res;
}
i128 i128_mod(i128 a, i128 b) {
i128 res = {0};
i128_divide(a, b, nullptr, &res);
return res;
}
+2907 -2354
View File
File diff suppressed because it is too large Load Diff
+57 -54
View File
@@ -1,6 +1,6 @@
// Optimizations for the IR code // Optimizations for the IR code
void ir_opt_add_operands(irValueArray *ops, irInstr *i) { void ir_opt_add_operands(Array<irValue *> *ops, irInstr *i) {
switch (i->kind) { switch (i->kind) {
case irInstr_Comment: case irInstr_Comment:
break; break;
@@ -39,7 +39,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
array_add(ops, i->If.cond); array_add(ops, i->If.cond);
break; break;
case irInstr_Return: case irInstr_Return:
if (i->Return.value != NULL) { if (i->Return.value != nullptr) {
array_add(ops, i->Return.value); array_add(ops, i->Return.value);
} }
break; break;
@@ -48,7 +48,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
break; break;
case irInstr_Phi: case irInstr_Phi:
for_array(j, i->Phi.edges) { for_array(j, i->Phi.edges) {
array_add(ops, i->Phi.edges.e[j]); array_add(ops, i->Phi.edges[j]);
} }
break; break;
case irInstr_Unreachable: case irInstr_Unreachable:
@@ -80,6 +80,8 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
// break; // break;
case irInstr_StartupRuntime: case irInstr_StartupRuntime:
break; break;
#if 0
case irInstr_BoundsCheck: case irInstr_BoundsCheck:
array_add(ops, i->BoundsCheck.index); array_add(ops, i->BoundsCheck.index);
array_add(ops, i->BoundsCheck.len); array_add(ops, i->BoundsCheck.len);
@@ -88,6 +90,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
array_add(ops, i->SliceBoundsCheck.low); array_add(ops, i->SliceBoundsCheck.low);
array_add(ops, i->SliceBoundsCheck.high); array_add(ops, i->SliceBoundsCheck.high);
break; break;
#endif
} }
} }
@@ -97,24 +100,24 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) { void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) {
for_array(i, b->preds) { for_array(i, b->preds) {
irBlock *pred = b->preds.e[i]; irBlock *pred = b->preds[i];
if (pred == from) { if (pred == from) {
b->preds.e[i] = to; b->preds[i] = to;
} }
} }
} }
void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) { void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) {
for_array(i, b->succs) { for_array(i, b->succs) {
irBlock *succ = b->succs.e[i]; irBlock *succ = b->succs[i];
if (succ == from) { if (succ == from) {
b->succs.e[i] = to; b->succs[i] = to;
} }
} }
} }
bool ir_opt_block_has_phi(irBlock *b) { bool ir_opt_block_has_phi(irBlock *b) {
return b->instrs.e[0]->Instr.kind == irInstr_Phi; return b->instrs[0]->Instr.kind == irInstr_Phi;
} }
@@ -126,10 +129,10 @@ bool ir_opt_block_has_phi(irBlock *b) {
irValueArray ir_get_block_phi_nodes(irBlock *b) { Array<irValue *> ir_get_block_phi_nodes(irBlock *b) {
irValueArray phis = {0}; Array<irValue *> phis = {0};
for_array(i, b->instrs) { for_array(i, b->instrs) {
irInstr *instr = &b->instrs.e[i]->Instr; irInstr *instr = &b->instrs[i]->Instr;
if (instr->kind != irInstr_Phi) { if (instr->kind != irInstr_Phi) {
phis = b->instrs; phis = b->instrs;
phis.count = i; phis.count = i;
@@ -140,22 +143,22 @@ irValueArray ir_get_block_phi_nodes(irBlock *b) {
} }
void ir_remove_pred(irBlock *b, irBlock *p) { void ir_remove_pred(irBlock *b, irBlock *p) {
irValueArray phis = ir_get_block_phi_nodes(b); Array<irValue *> phis = ir_get_block_phi_nodes(b);
isize i = 0; isize i = 0;
for_array(j, b->preds) { for_array(j, b->preds) {
irBlock *pred = b->preds.e[j]; irBlock *pred = b->preds[j];
if (pred != p) { if (pred != p) {
b->preds.e[i] = b->preds.e[j]; b->preds[i] = b->preds[j];
for_array(k, phis) { for_array(k, phis) {
irInstrPhi *phi = &phis.e[k]->Instr.Phi; irInstrPhi *phi = &phis[k]->Instr.Phi;
phi->edges.e[i] = phi->edges.e[j]; phi->edges[i] = phi->edges[j];
} }
i++; i++;
} }
} }
b->preds.count = i; b->preds.count = i;
for_array(k, phis) { for_array(k, phis) {
irInstrPhi *phi = &phis.e[k]->Instr.Phi; irInstrPhi *phi = &phis[k]->Instr.Phi;
phi->edges.count = i; phi->edges.count = i;
} }
@@ -164,13 +167,13 @@ void ir_remove_pred(irBlock *b, irBlock *p) {
void ir_remove_dead_blocks(irProcedure *proc) { void ir_remove_dead_blocks(irProcedure *proc) {
isize j = 0; isize j = 0;
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i]; irBlock *b = proc->blocks[i];
if (b == NULL) { if (b == nullptr) {
continue; continue;
} }
// NOTE(bill): Swap order // NOTE(bill): Swap order
b->index = j; b->index = cast(i32)j;
proc->blocks.e[j++] = b; proc->blocks[j++] = b;
} }
proc->blocks.count = j; proc->blocks.count = j;
} }
@@ -180,7 +183,7 @@ void ir_mark_reachable(irBlock *b) {
isize const BLACK = -1; isize const BLACK = -1;
b->index = BLACK; b->index = BLACK;
for_array(i, b->succs) { for_array(i, b->succs) {
irBlock *succ = b->succs.e[i]; irBlock *succ = b->succs[i];
if (succ->index == WHITE) { if (succ->index == WHITE) {
ir_mark_reachable(succ); ir_mark_reachable(succ);
} }
@@ -191,23 +194,23 @@ void ir_remove_unreachable_blocks(irProcedure *proc) {
isize const WHITE = 0; isize const WHITE = 0;
isize const BLACK = -1; isize const BLACK = -1;
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
proc->blocks.e[i]->index = WHITE; proc->blocks[i]->index = WHITE;
} }
ir_mark_reachable(proc->blocks.e[0]); ir_mark_reachable(proc->blocks[0]);
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i]; irBlock *b = proc->blocks[i];
if (b->index == WHITE) { if (b->index == WHITE) {
for_array(j, b->succs) { for_array(j, b->succs) {
irBlock *c = b->succs.e[j]; irBlock *c = b->succs[j];
if (c->index == BLACK) { if (c->index == BLACK) {
ir_remove_pred(c, b); ir_remove_pred(c, b);
} }
} }
// NOTE(bill): Mark as empty but don't actually free it // NOTE(bill): Mark as empty but don't actually free it
// As it's been allocated with an arena // As it's been allocated with an arena
proc->blocks.e[i] = NULL; proc->blocks[i] = nullptr;
} }
} }
ir_remove_dead_blocks(proc); ir_remove_dead_blocks(proc);
@@ -217,7 +220,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
if (a->succs.count != 1) { if (a->succs.count != 1) {
return false; return false;
} }
irBlock *b = a->succs.e[0]; irBlock *b = a->succs[0];
if (b->preds.count != 1) { if (b->preds.count != 1) {
return false; return false;
} }
@@ -228,21 +231,21 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
array_pop(&a->instrs); // Remove branch at end array_pop(&a->instrs); // Remove branch at end
for_array(i, b->instrs) { for_array(i, b->instrs) {
array_add(&a->instrs, b->instrs.e[i]); array_add(&a->instrs, b->instrs[i]);
ir_set_instr_parent(b->instrs.e[i], a); ir_set_instr_parent(b->instrs[i], a);
} }
array_clear(&a->succs); array_clear(&a->succs);
for_array(i, b->succs) { for_array(i, b->succs) {
array_add(&a->succs, b->succs.e[i]); array_add(&a->succs, b->succs[i]);
} }
// Fix preds links // Fix preds links
for_array(i, b->succs) { for_array(i, b->succs) {
ir_opt_block_replace_pred(b->succs.e[i], b, a); ir_opt_block_replace_pred(b->succs[i], b, a);
} }
proc->blocks.e[b->index] = NULL; proc->blocks[b->index] = nullptr;
return true; return true;
} }
@@ -254,8 +257,8 @@ void ir_opt_blocks(irProcedure *proc) {
while (changed) { while (changed) {
changed = false; changed = false;
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i]; irBlock *b = proc->blocks[i];
if (b == NULL) { if (b == nullptr) {
continue; continue;
} }
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i); GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
@@ -273,21 +276,21 @@ void ir_opt_blocks(irProcedure *proc) {
void ir_opt_build_referrers(irProcedure *proc) { void ir_opt_build_referrers(irProcedure *proc) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
irValueArray ops = {0}; // NOTE(bill): Act as a buffer Array<irValue *> ops = {0}; // NOTE(bill): Act as a buffer
array_init_reserve(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena array_init(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i]; irBlock *b = proc->blocks[i];
for_array(j, b->instrs) { for_array(j, b->instrs) {
irValue *instr = b->instrs.e[j]; irValue *instr = b->instrs[j];
array_clear(&ops); array_clear(&ops);
ir_opt_add_operands(&ops, &instr->Instr); ir_opt_add_operands(&ops, &instr->Instr);
for_array(k, ops) { for_array(k, ops) {
irValue *op = ops.e[k]; irValue *op = ops[k];
if (op == NULL) { if (op == nullptr) {
continue; continue;
} }
irValueArray *refs = ir_value_referrers(op); Array<irValue *> *refs = ir_value_referrers(op);
if (refs != NULL) { if (refs != nullptr) {
array_add(refs, instr); array_add(refs, instr);
} }
} }
@@ -322,10 +325,10 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
preorder[i] = p; preorder[i] = p;
p->dom.pre = i++; p->dom.pre = i++;
lt->sdom[p->index] = p; lt->sdom[p->index] = p;
ir_lt_link(lt, NULL, p); ir_lt_link(lt, nullptr, p);
for_array(index, p->succs) { for_array(index, p->succs) {
irBlock *q = p->succs.e[index]; irBlock *q = p->succs[index];
if (lt->sdom[q->index] == NULL) { if (lt->sdom[q->index] == nullptr) {
lt->parent[q->index] = p; lt->parent[q->index] = p;
i = ir_lt_depth_first_search(lt, q, i, preorder); i = ir_lt_depth_first_search(lt, q, i, preorder);
} }
@@ -336,7 +339,7 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
irBlock *ir_lt_eval(irLTState *lt, irBlock *v) { irBlock *ir_lt_eval(irLTState *lt, irBlock *v) {
irBlock *u = v; irBlock *u = v;
for (; for (;
lt->ancestor[v->index] != NULL; lt->ancestor[v->index] != nullptr;
v = lt->ancestor[v->index]) { v = lt->ancestor[v->index]) {
if (lt->sdom[v->index]->dom.pre < lt->sdom[u->index]->dom.pre) { if (lt->sdom[v->index]->dom.pre < lt->sdom[u->index]->dom.pre) {
u = v; u = v;
@@ -354,7 +357,7 @@ irDomPrePost ir_opt_number_dom_tree(irBlock *v, i32 pre, i32 post) {
v->dom.pre = pre++; v->dom.pre = pre++;
for_array(i, v->dom.children) { for_array(i, v->dom.children) {
result = ir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post); result = ir_opt_number_dom_tree(v->dom.children[i], result.pre, result.post);
} }
v->dom.post = post++; v->dom.post = post++;
@@ -370,7 +373,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
isize n = proc->blocks.count; i32 n = cast(i32)proc->blocks.count;
irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n); irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n);
irLTState lt = {0}; irLTState lt = {0};
@@ -381,7 +384,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
irBlock **preorder = &buf[3*n]; irBlock **preorder = &buf[3*n];
irBlock **buckets = &buf[4*n]; irBlock **buckets = &buf[4*n];
irBlock *root = proc->blocks.e[0]; irBlock *root = proc->blocks[0];
// Step 1 - number vertices // Step 1 - number vertices
i32 pre_num = ir_lt_depth_first_search(&lt, root, 0, preorder); i32 pre_num = ir_lt_depth_first_search(&lt, root, 0, preorder);
@@ -403,7 +406,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
// Step 2 - Compute all sdoms // Step 2 - Compute all sdoms
lt.sdom[w->index] = lt.parent[w->index]; lt.sdom[w->index] = lt.parent[w->index];
for_array(pred_index, w->preds) { for_array(pred_index, w->preds) {
irBlock *v = w->preds.e[pred_index]; irBlock *v = w->preds[pred_index];
irBlock *u = ir_lt_eval(&lt, v); irBlock *u = ir_lt_eval(&lt, v);
if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) { if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) {
lt.sdom[w->index] = lt.sdom[u->index]; lt.sdom[w->index] = lt.sdom[u->index];
@@ -429,7 +432,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
for (isize i = 1; i < n; i++) { for (isize i = 1; i < n; i++) {
irBlock *w = preorder[i]; irBlock *w = preorder[i];
if (w == root) { if (w == root) {
w->dom.idom = NULL; w->dom.idom = nullptr;
} else { } else {
// Weird tree relationships here! // Weird tree relationships here!
@@ -438,7 +441,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
} }
// Calculate children relation as inverse of idom // Calculate children relation as inverse of idom
if (w->dom.idom->dom.children.e == NULL) { if (w->dom.idom->dom.children.data == nullptr) {
// TODO(bill): Is this good enough for memory allocations? // TODO(bill): Is this good enough for memory allocations?
array_init(&w->dom.idom->dom.children, heap_allocator()); array_init(&w->dom.idom->dom.children, heap_allocator());
} }
@@ -461,7 +464,7 @@ void ir_opt_tree(irGen *s) {
s->opt_called = true; s->opt_called = true;
for_array(member_index, s->module.procs) { for_array(member_index, s->module.procs) {
irProcedure *proc = s->module.procs.e[member_index]; irProcedure *proc = s->module.procs[member_index];
if (proc->blocks.count == 0) { // Prototype/external procedure if (proc->blocks.count == 0) { // Prototype/external procedure
continue; continue;
} }
File diff suppressed because it is too large Load Diff
-468
View File
@@ -1,468 +0,0 @@
#if defined(__cplusplus)
extern "C" {
#endif
#define USE_CUSTOM_BACKEND false
#include "common.c"
#include "timings.c"
#include "build_settings.c"
#include "tokenizer.c"
#include "parser.c"
#include "checker.c"
#include "ssa.c"
#include "ir.c"
#include "ir_opt.c"
#include "ir_print.c"
// #include "vm.c"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
PROCESS_INFORMATION pi = {0};
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
gbTempArenaMemory tmp;
String16 cmd;
i32 exit_code = 0;
start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_SHOW;
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
// gb_printf("%.*s\n", cast(int)cmd_len, cmd_line);
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
if (CreateProcessW(NULL, cmd.text,
NULL, NULL, true, 0, NULL, NULL,
&start_info, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
} else {
// NOTE(bill): failed to create process
gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
exit_code = -1;
}
gb_temp_arena_memory_end(tmp);
return exit_code;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
String cmd;
i32 exit_code = 0;
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
// int status = 0;
// if(pid == 0) {
// // in child, pid == 0.
// int ret = execvp(cmd.text, (char* const*) cmd.text);
// if(ret == -1) {
// gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
// // we're in the child, so returning won't do us any good -- just quit.
// exit(-1);
// }
// // unreachable
// abort();
// } else {
// // wait for child to finish, then we can continue cleanup
// int s = 0;
// waitpid(pid, &s, 0);
// status = WEXITSTATUS(s);
// }
// exit_code = status;
return exit_code;
}
#endif
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
gb_printf_err("\t");
}
va_list va;
va_start(va, fmt);
gb_printf_err_va(fmt, va);
va_end(va);
gb_printf_err("\n");
}
void usage(char *argv0) {
print_usage_line(0, "%s is a tool for managing Odin source code", argv0);
print_usage_line(0, "Usage:");
print_usage_line(1, "%s command [arguments]", argv0);
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable");
print_usage_line(1, "build_dll compile .odin file as dll");
print_usage_line(1, "run compile and run .odin file");
print_usage_line(1, "version print version");
}
int main(int argc, char **argv) {
if (argc < 2) {
usage(argv[0]);
return 1;
}
Timings timings = {0};
timings_init(&timings, str_lit("Total Time"), 128);
// defer (timings_destroy(&timings));
init_string_buffer_memory();
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
#if 1
init_build_context();
init_universal_scope();
char *init_filename = NULL;
bool run_output = false;
String arg1 = make_string_c(argv[1]);
if (str_eq(arg1, str_lit("run"))) {
if (argc != 3) {
usage(argv[0]);
return 1;
}
init_filename = argv[2];
run_output = true;
} else if (str_eq(arg1, str_lit("build_dll"))) {
if (argc != 3) {
usage(argv[0]);
return 1;
}
init_filename = argv[2];
build_context.is_dll = true;
} else if (str_eq(arg1, str_lit("build"))) {
if (argc != 3) {
usage(argv[0]);
return 1;
}
init_filename = argv[2];
} else if (str_eq(arg1, str_lit("version"))) {
gb_printf("%s version %.*s", argv[0], LIT(build_context.ODIN_VERSION));
return 0;
} else {
usage(argv[0]);
return 1;
}
// TODO(bill): prevent compiling without a linker
timings_start_section(&timings, str_lit("parse files"));
Parser parser = {0};
if (!init_parser(&parser)) {
return 1;
}
// defer (destroy_parser(&parser));
if (parse_files(&parser, init_filename) != ParseFile_None) {
return 1;
}
#if 1
timings_start_section(&timings, str_lit("type check"));
Checker checker = {0};
init_checker(&checker, &parser, &build_context);
// defer (destroy_checker(&checker));
check_parsed_files(&checker);
#endif
#if USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}
if (checker.parser->total_token_count < 2) {
return 1;
}
if (!ssa_generate(&parser, &checker.info)) {
return 1;
}
#else
irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker)) {
return 1;
}
// defer (ssa_gen_destroy(&ir_gen));
timings_start_section(&timings, str_lit("llvm ir gen"));
ir_gen_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir opt tree"));
ir_opt_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir print"));
print_llvm_ir(&ir_gen);
// prof_print_all();
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
String output_name = ir_gen.output_name;
String output_base = ir_gen.output_base;
int base_name_len = output_base.len;
i32 optimization_level = 0;
optimization_level = gb_clamp(optimization_level, 0, 3);
i32 exit_code = 0;
#if defined(GB_SYSTEM_WINDOWS)
// For more passes arguments: http://llvm.org/docs/Passes.html
exit_code = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%.*s\".ll -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
"-die "
// "-dse "
// "-dce "
// "-S "
"",
LIT(build_context.ODIN_ROOT),
LIT(output_base), LIT(output_base));
if (exit_code != 0) {
return exit_code;
}
#else
// NOTE(zangent): This is separate because it seems that LLVM tools are packaged
// with the Windows version, while they will be system-provided on MacOS and GNU/Linux
exit_code = system_exec_command_line_app("llvm-opt", false,
"opt \"%.*s\".ll -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
"-die "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `macosx_version_min` param passed to `llc`
"-mtriple=x86_64-apple-macosx10.8 "
#endif
// "-dse "
// "-dce "
// "-S "
"",
LIT(output_base), LIT(output_base));
if (exit_code != 0) {
return exit_code;
}
#endif
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = system_exec_command_line_app("llvm-llc", false,
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(build_context.ODIN_ROOT),
LIT(output_base),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("msvc-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
// defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths.e[i];
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" \"%.*s\"", LIT(lib));
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
char *output_ext = "exe";
char *link_settings = "";
if (build_context.is_dll) {
output_ext = "dll";
link_settings = "/DLL";
} else {
link_settings = "/ENTRY:mainCRTStartup";
}
exit_code = system_exec_command_line_app("msvc-link", true,
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
"/defaultlib:libcmt "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
" %s "
"",
LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
// timings_print_all(&timings);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
}
#else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = system_exec_command_line_app("llc", false,
"llc \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(output_base),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("ld-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
// defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths.e[i];
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
isize len;
if(lib.len > 2 && lib.text[0] == '-' && lib.text[1] == 'f') {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
} else {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
}
#else
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
#endif
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
// Unlike the Win32 linker code, the output_ext includes the dot, because
// typically executable files on *NIX systems don't have extensions.
char *output_ext = "";
char *link_settings = "";
char *linker;
if (build_context.is_dll) {
// Shared libraries are .dylib on MacOS and .so on Linux.
// TODO(zangent): Is that statement entirely truthful?
#if defined(GB_SYSTEM_OSX)
output_ext = ".dylib";
#else
output_ext = ".so";
#endif
link_settings = "-shared";
} else {
// TODO: Do I need anything here?
link_settings = "";
}
#if defined(GB_SYSTEM_OSX)
linker = "ld";
#else
// TODO(zangent): Figure out how to make ld work on Linux.
// It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_.
linker = "clang -Wno-unused-command-line-argument";
#endif
exit_code = system_exec_command_line_app("ld-link", true,
"%s \"%.*s\".o -o \"%.*s%s\" %s "
"-lc -lm "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `mtriple` param passed to `opt`
" -macosx_version_min 10.8.0 "
// This points the linker to where the entry point is
" -e _main "
#endif
, linker, LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
// timings_print_all(&timings);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
}
#endif
#endif
#endif
#endif
return 0;
}
#if defined(__cplusplus)
}
#endif
+796
View File
@@ -0,0 +1,796 @@
#define USE_CUSTOM_BACKEND 0
// #define NO_ARRAY_BOUNDS_CHECK
#if !defined(USE_THREADED_PARSER)
#define USE_THREADED_PARSER 0
#endif
#include "common.cpp"
#include "timings.cpp"
#include "build_settings.cpp"
#include "tokenizer.cpp"
#include "parser.cpp"
#include "docs.cpp"
#include "checker.cpp"
#include "ssa.cpp"
#include "ir.cpp"
#include "ir_opt.cpp"
#include "ir_print.cpp"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
PROCESS_INFORMATION pi = {0};
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
gbTempArenaMemory tmp;
String16 cmd;
i32 exit_code = 0;
start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_SHOW;
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
// gb_printf_err("%.*s\n", cast(int)cmd_len, cmd_line);
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
if (CreateProcessW(nullptr, cmd.text,
nullptr, nullptr, true, 0, nullptr, nullptr,
&start_info, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
} else {
// NOTE(bill): failed to create process
gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
exit_code = -1;
}
gb_temp_arena_memory_end(tmp);
return exit_code;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
String cmd;
i32 exit_code = 0;
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
// int status = 0;
// if(pid == 0) {
// // in child, pid == 0.
// int ret = execvp(cmd.text, (char* const*) cmd.text);
// if(ret == -1) {
// gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
// // we're in the child, so returning won't do us any good -- just quit.
// exit(-1);
// }
// // unreachable
// abort();
// } else {
// // wait for child to finish, then we can continue cleanup
// int s = 0;
// waitpid(pid, &s, 0);
// status = WEXITSTATUS(s);
// }
// exit_code = status;
return exit_code;
}
#endif
Array<String> setup_args(int argc, char **argv) {
Array<String> args = {};
gbAllocator a = heap_allocator();
int i;
#if defined(GB_SYSTEM_WINDOWS)
int wargc = 0;
wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc);
array_init(&args, a, wargc);
for (i = 0; i < wargc; i++) {
wchar_t *warg = wargv[i];
isize wlen = string16_len(warg);
String16 wstr = make_string16(warg, wlen);
String arg = string16_to_string(a, wstr);
if (arg.len > 0) {
array_add(&args, arg);
}
}
#else
array_init(&args, a, argc);
for (i = 0; i < argc; i++) {
String arg = make_string_c(argv[i]);
if (arg.len > 0) {
array_add(&args, arg);
}
}
#endif
return args;
}
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
gb_printf_err("\t");
}
va_list va;
va_start(va, fmt);
gb_printf_err_va(fmt, va);
va_end(va);
gb_printf_err("\n");
}
void usage(String argv0) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable");
print_usage_line(1, "build_dll compile .odin file as dll");
print_usage_line(1, "run compile and run .odin file");
print_usage_line(1, "docs generate documentation for a .odin file");
print_usage_line(1, "version print version");
}
enum BuildFlagKind {
BuildFlag_Invalid,
BuildFlag_OptimizationLevel,
BuildFlag_ShowTimings,
BuildFlag_ThreadCount,
BuildFlag_KeepTempFiles,
BuildFlag_COUNT,
};
enum BuildFlagParamKind {
BuildFlagParam_None,
BuildFlagParam_Boolean,
BuildFlagParam_Integer,
BuildFlagParam_Float,
BuildFlagParam_String,
BuildFlagParam_COUNT,
};
struct BuildFlag {
BuildFlagKind kind;
String name;
BuildFlagParamKind param_kind;
};
void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind) {
BuildFlag flag = {kind, name, param_kind};
array_add(build_flags, flag);
}
bool parse_build_flags(Array<String> args) {
Array<BuildFlag> build_flags = {};
array_init(&build_flags, heap_allocator(), BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
Array<String> flag_args = args;
flag_args.data += 3;
flag_args.count -= 3;
bool set_flags[BuildFlag_COUNT] = {};
bool bad_flags = false;
for_array(i, flag_args) {
String flag = flag_args[i];
if (flag[0] != '-') {
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
continue;
}
String name = substring(flag, 1, flag.len);
isize end = 0;
for (; end < name.len; end++) {
if (name[end] == '=') break;
}
name = substring(name, 0, end);
String param = {};
if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
bool found = false;
for_array(build_flag_index, build_flags) {
BuildFlag bf = build_flags[build_flag_index];
if (bf.name == name) {
found = true;
if (set_flags[bf.kind]) {
gb_printf_err("Previous flag set: `%.*s`\n", LIT(name));
bad_flags = true;
} else {
ExactValue value = {};
bool ok = false;
if (bf.param_kind == BuildFlagParam_None) {
if (param.len == 0) {
ok = true;
} else {
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param));
bad_flags = true;
}
} else if (param.len == 0) {
gb_printf_err("Flag missing for `%.*s`\n", LIT(name));
bad_flags = true;
} else {
ok = true;
switch (bf.param_kind) {
default: ok = false; break;
case BuildFlagParam_Boolean: {
if (param == "t") {
value = exact_value_bool(true);
} else if (param == "T") {
value = exact_value_bool(true);
} else if (param == "true") {
value = exact_value_bool(true);
} else if (param == "TRUE") {
value = exact_value_bool(true);
} else if (param == "1") {
value = exact_value_bool(true);
} else if (param == "f") {
value = exact_value_bool(false);
} else if (param == "F") {
value = exact_value_bool(false);
} else if (param == "false") {
value = exact_value_bool(false);
} else if (param == "FALSE") {
value = exact_value_bool(false);
} else if (param == "0") {
value = exact_value_bool(false);
} else {
gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
}
} break;
case BuildFlagParam_Integer:
value = exact_value_integer_from_string(param);
break;
case BuildFlagParam_Float:
value = exact_value_float_from_string(param);
break;
case BuildFlagParam_String:
value = exact_value_string(param);
break;
}
}
if (ok) {
switch (bf.param_kind) {
case BuildFlagParam_None:
if (value.kind != ExactValue_Invalid) {
gb_printf_err("%.*s expected no value, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_Boolean:
if (value.kind != ExactValue_Bool) {
gb_printf_err("%.*s expected a boolean, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_Integer:
if (value.kind != ExactValue_Integer) {
gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_Float:
if (value.kind != ExactValue_Float) {
gb_printf_err("%.*s expected a floating pointer number, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_String:
if (value.kind != ExactValue_String) {
gb_printf_err("%.*s expected a string, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
}
if (ok) switch (bf.kind) {
case BuildFlag_OptimizationLevel:
GB_ASSERT(value.kind == ExactValue_Integer);
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
break;
case BuildFlag_ShowTimings:
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.show_timings = true;
break;
case BuildFlag_ThreadCount: {
GB_ASSERT(value.kind == ExactValue_Integer);
isize count = cast(isize)i128_to_i64(value.value_integer);
if (count <= 0) {
gb_printf_err("%.*s expected a positive non-zero number, got %.*s", LIT(name), LIT(param));
build_context.thread_count = 0;
} else {
build_context.thread_count = count;
}
} break;
case BuildFlag_KeepTempFiles:
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.keep_temp_files = true;
break;
}
}
set_flags[bf.kind] = ok;
}
break;
}
}
if (!found) {
gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
bad_flags = true;
}
}
return !bad_flags;
}
void show_timings(Checker *c, Timings *t) {
Parser *p = c->parser;
isize lines = p->total_line_count;
isize tokens = p->total_token_count;
isize files = p->files.count;
{
timings_print_all(t);
gb_printf("\n");
gb_printf("Total Lines - %td\n", lines);
gb_printf("Total Tokens - %td\n", tokens);
gb_printf("Total Files - %td\n", files);
gb_printf("\n");
}
{
TimeStamp ts = t->sections[0];
GB_ASSERT(ts.label == "parse files");
f64 parse_time = time_stamp_as_second(ts, t->freq);
gb_printf("Parse pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
gb_printf("\n");
}
{
f64 total_time = t->total_time_seconds;
gb_printf("Total pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
gb_printf("\n");
}
}
void remove_temp_files(String output_base) {
if (build_context.keep_temp_files) return;
Array<u8> data = {};
array_init_count(&data, heap_allocator(), output_base.len + 10);
defer (array_free(&data));
isize n = output_base.len;
gb_memcopy(data.data, output_base.text, n);
#define EXT_REMOVE(s) do { \
gb_memcopy(data.data+n, s, gb_size_of(s)); \
gb_file_remove(cast(char *)data.data); \
} while (0)
EXT_REMOVE(".ll");
EXT_REMOVE(".bc");
#if defined(GB_SYSTEM_WINDOWS)
EXT_REMOVE(".obj");
#else
EXT_REMOVE(".o");
#endif
#undef EXT_REMOVE
}
int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) {
usage(make_string_c(arg_ptr[0]));
return 1;
}
Timings timings = {0};
timings_init(&timings, str_lit("Total Time"), 128);
defer (timings_destroy(&timings));
init_string_buffer_memory();
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
Array<String> args = setup_args(arg_count, arg_ptr);
#if 1
String init_filename = {};
bool run_output = false;
if (args[1] == "run") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
run_output = true;
} else if (args[1] == "build_dll") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
build_context.is_dll = true;
} else if (args[1] == "build") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
} else if (args[1] == "docs") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
build_context.generate_docs = true;
#if 1
print_usage_line(0, "Documentation generation is not yet supported");
return 1;
#endif
} else if (args[1] == "version") {
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
return 0;
} else {
usage(args[0]);
return 1;
}
if (!parse_build_flags(args)) {
return 1;
}
init_build_context();
if (build_context.word_size == 4) {
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
return 1;
}
init_universal_scope();
// TODO(bill): prevent compiling without a linker
timings_start_section(&timings, str_lit("parse files"));
Parser parser = {0};
if (!init_parser(&parser)) {
return 1;
}
defer (destroy_parser(&parser));
if (parse_files(&parser, init_filename) != ParseFile_None) {
return 1;
}
if (build_context.generate_docs) {
generate_documentation(&parser);
return 0;
}
#if 1
timings_start_section(&timings, str_lit("type check"));
Checker checker = {0};
init_checker(&checker, &parser);
defer (destroy_checker(&checker));
check_parsed_files(&checker);
#endif
#if defined(USE_CUSTOM_BACKEND) && USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}
if (checker.parser->total_token_count < 2) {
return 1;
}
if (!ssa_generate(&parser, &checker.info)) {
return 1;
}
#else
irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker)) {
return 1;
}
defer (ir_gen_destroy(&ir_gen));
timings_start_section(&timings, str_lit("llvm ir gen"));
ir_gen_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir opt tree"));
ir_opt_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir print"));
print_llvm_ir(&ir_gen);
// prof_print_all();
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
String output_name = ir_gen.output_name;
String output_base = ir_gen.output_base;
int base_name_len = cast(int)output_base.len;
build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
i32 exit_code = 0;
#if defined(GB_SYSTEM_WINDOWS)
// For more passes arguments: http://llvm.org/docs/Passes.html
exit_code = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%.*s\".ll -o \"%.*s\".bc %.*s "
"-mem2reg "
"-memcpyopt "
"-die "
"",
LIT(build_context.ODIN_ROOT),
LIT(output_base), LIT(output_base),
LIT(build_context.opt_flags));
if (exit_code != 0) {
return exit_code;
}
#else
// NOTE(zangent): This is separate because it seems that LLVM tools are packaged
// with the Windows version, while they will be system-provided on MacOS and GNU/Linux
exit_code = system_exec_command_line_app("llvm-opt", false,
"opt \"%.*s\".ll -o \"%.*s\".bc %.*s "
"-mem2reg "
"-memcpyopt "
"-die "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `macosx_version_min` param passed to `llc`
"-mtriple=x86_64-apple-macosx10.8 "
#endif
"",
LIT(output_base), LIT(output_base),
LIT(build_context.opt_flags));
if (exit_code != 0) {
return exit_code;
}
#endif
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = system_exec_command_line_app("llvm-llc", false,
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(build_context.ODIN_ROOT),
LIT(output_base),
build_context.optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("msvc-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths[i];
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" \"%.*s\"", LIT(lib));
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
char *output_ext = "exe";
char *link_settings = "";
if (build_context.is_dll) {
output_ext = "dll";
link_settings = "/DLL";
} else {
link_settings = "/ENTRY:mainCRTStartup";
}
exit_code = system_exec_command_line_app("msvc-link", true,
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
"/defaultlib:libcmt "
// "/nodefaultlib "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
" %s "
"",
LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
if (build_context.show_timings) {
show_timings(&checker, &timings);
}
remove_temp_files(output_base);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
}
#else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = system_exec_command_line_app("llc", false,
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(output_base),
build_context.optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("ld-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths[i];
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
isize len;
if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
} else {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
}
#else
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
#endif
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
// Unlike the Win32 linker code, the output_ext includes the dot, because
// typically executable files on *NIX systems don't have extensions.
char *output_ext = "";
char *link_settings = "";
char *linker;
if (build_context.is_dll) {
// Shared libraries are .dylib on MacOS and .so on Linux.
// TODO(zangent): Is that statement entirely truthful?
#if defined(GB_SYSTEM_OSX)
output_ext = ".dylib";
#else
output_ext = ".so";
#endif
link_settings = "-shared";
} else {
// TODO: Do I need anything here?
link_settings = "";
}
#if defined(GB_SYSTEM_OSX)
linker = "ld";
#else
// TODO(zangent): Figure out how to make ld work on Linux.
// It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_.
linker = "clang -Wno-unused-command-line-argument";
#endif
exit_code = system_exec_command_line_app("ld-link", true,
"%s \"%.*s\".o -o \"%.*s%s\" %s "
"-lc -lm "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `mtriple` param passed to `opt`
" -macosx_version_min 10.8.0 "
// This points the linker to where the entry point is
" -e _main "
#endif
, linker, LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
if (build_context.show_timings) {
show_timings(&checker, &timings);
}
remove_temp_files(output_base);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
}
#endif
#endif
#endif
#endif
return 0;
}
-361
View File
@@ -1,361 +0,0 @@
/*
Example of usage:
#define MAP_TYPE String
#define MAP_PROC map_string_
#define MAP_NAME MapString
#include "map.c"
*/
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
// NOTE(bill): This util stuff is the same for every `Map`
typedef struct MapFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
} MapFindResult;
typedef enum HashKeyKind {
HashKey_Default,
HashKey_String,
HashKey_Pointer,
} HashKeyKind;
typedef struct HashKey {
HashKeyKind kind;
u64 key;
union {
String string; // if String, s.len > 0
void * ptr;
};
} HashKey;
gb_inline HashKey hashing_proc(void const *data, isize len) {
HashKey h = {HashKey_Default};
h.kind = HashKey_Default;
// h.key = gb_murmur64(data, len);
h.key = gb_fnv64a(data, len);
return h;
}
gb_inline HashKey hash_string(String s) {
HashKey h = hashing_proc(s.text, s.len);
h.kind = HashKey_String;
h.string = s;
return h;
}
gb_inline HashKey hash_pointer(void *ptr) {
HashKey h = {HashKey_Default};
h.key = cast(u64)cast(uintptr)ptr;
h.ptr = ptr;
h.kind = HashKey_Default;
return h;
}
bool hash_key_equal(HashKey a, HashKey b) {
if (a.key == b.key) {
// NOTE(bill): If two string's hashes collide, compare the strings themselves
if (a.kind == HashKey_String) {
if (b.kind == HashKey_String) {
return str_eq(a.string, b.string);
}
return false;
}
return true;
}
return false;
}
#endif
#define _J2_IND(a, b) a##b
#define _J2(a, b) _J2_IND(a, b)
/*
MAP_TYPE - Entry type
MAP_PROC - Function prefix (e.g. entity_map_)
MAP_NAME - Name of Map (e.g. EntityMap)
*/
#define MAP_ENTRY _J2(MAP_NAME,Entry)
typedef struct MAP_ENTRY {
HashKey key;
isize next;
MAP_TYPE value;
} MAP_ENTRY;
typedef struct MAP_NAME {
Array(isize) hashes;
Array(MAP_ENTRY) entries;
} MAP_NAME;
void _J2(MAP_PROC,init) (MAP_NAME *h, gbAllocator a);
void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity);
void _J2(MAP_PROC,destroy) (MAP_NAME *h);
MAP_TYPE *_J2(MAP_PROC,get) (MAP_NAME *h, HashKey key);
void _J2(MAP_PROC,set) (MAP_NAME *h, HashKey key, MAP_TYPE value);
void _J2(MAP_PROC,remove) (MAP_NAME *h, HashKey key);
void _J2(MAP_PROC,clear) (MAP_NAME *h);
void _J2(MAP_PROC,grow) (MAP_NAME *h);
void _J2(MAP_PROC,rehash) (MAP_NAME *h, isize new_count);
// Mutlivalued map procedure
MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key);
MAP_ENTRY *_J2(MAP_PROC,multi_find_next) (MAP_NAME *h, MAP_ENTRY *e);
isize _J2(MAP_PROC,multi_count) (MAP_NAME *h, HashKey key);
void _J2(MAP_PROC,multi_get_all) (MAP_NAME *h, HashKey key, MAP_TYPE *items);
void _J2(MAP_PROC,multi_insert) (MAP_NAME *h, HashKey key, MAP_TYPE value);
void _J2(MAP_PROC,multi_remove) (MAP_NAME *h, HashKey key, MAP_ENTRY *e);
void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key);
gb_inline void _J2(MAP_PROC,init)(MAP_NAME *h, gbAllocator a) {
array_init(&h->hashes, a);
array_init(&h->entries, a);
}
gb_inline void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) {
array_init_reserve(&h->hashes, a, capacity);
array_init_reserve(&h->entries, a, capacity);
}
gb_inline void _J2(MAP_PROC,destroy)(MAP_NAME *h) {
array_free(&h->entries);
array_free(&h->hashes);
}
gb_internal isize _J2(MAP_PROC,_add_entry)(MAP_NAME *h, HashKey key) {
MAP_ENTRY e = {0};
e.key = key;
e.next = -1;
array_add(&h->entries, e);
return h->entries.count-1;
}
gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
fr.hash_index = key.key % h->hashes.count;
fr.entry_index = h->hashes.e[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.e[fr.entry_index].next;
}
}
return fr;
}
gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY *e) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
fr.hash_index = e->key.key % h->hashes.count;
fr.entry_index = h->hashes.e[fr.hash_index];
while (fr.entry_index >= 0) {
if (&h->entries.e[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.e[fr.entry_index].next;
}
}
return fr;
}
gb_internal b32 _J2(MAP_PROC,_full)(MAP_NAME *h) {
return 0.75f * h->hashes.count <= h->entries.count;
}
gb_inline void _J2(MAP_PROC,grow)(MAP_NAME *h) {
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
_J2(MAP_PROC,rehash)(h, new_count);
}
void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) {
isize i, j;
MAP_NAME nh = {0};
_J2(MAP_PROC,init)(&nh, h->hashes.allocator);
array_resize(&nh.hashes, new_count);
array_reserve(&nh.entries, h->entries.count);
for (i = 0; i < new_count; i++) {
nh.hashes.e[i] = -1;
}
for (i = 0; i < h->entries.count; i++) {
MAP_ENTRY *e = &h->entries.e[i];
MapFindResult fr;
if (nh.hashes.count == 0) {
_J2(MAP_PROC,grow)(&nh);
}
fr = _J2(MAP_PROC,_find)(&nh, e->key);
j = _J2(MAP_PROC,_add_entry)(&nh, e->key);
if (fr.entry_prev < 0) {
nh.hashes.e[fr.hash_index] = j;
} else {
nh.entries.e[fr.entry_prev].next = j;
}
nh.entries.e[j].next = fr.entry_index;
nh.entries.e[j].value = e->value;
if (_J2(MAP_PROC,_full)(&nh)) {
_J2(MAP_PROC,grow)(&nh);
}
}
_J2(MAP_PROC,destroy)(h);
*h = nh;
}
gb_inline MAP_TYPE *_J2(MAP_PROC,get)(MAP_NAME *h, HashKey key) {
isize index = _J2(MAP_PROC,_find)(h, key).entry_index;
if (index >= 0) {
return &h->entries.e[index].value;
}
return NULL;
}
void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
isize index;
MapFindResult fr;
if (h->hashes.count == 0)
_J2(MAP_PROC,grow)(h);
fr = _J2(MAP_PROC,_find)(h, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = _J2(MAP_PROC,_add_entry)(h, key);
if (fr.entry_prev >= 0) {
h->entries.e[fr.entry_prev].next = index;
} else {
h->hashes.e[fr.hash_index] = index;
}
}
h->entries.e[index].value = value;
if (_J2(MAP_PROC,_full)(h)) {
_J2(MAP_PROC,grow)(h);
}
}
void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev < 0) {
h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next;
} else {
h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
return;
}
h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1];
last = _J2(MAP_PROC,_find)(h, h->entries.e[fr.entry_index].key);
if (last.entry_prev >= 0) {
h->entries.e[last.entry_prev].next = fr.entry_index;
} else {
h->hashes.e[last.hash_index] = fr.entry_index;
}
}
void _J2(MAP_PROC,remove)(MAP_NAME *h, HashKey key) {
MapFindResult fr = _J2(MAP_PROC,_find)(h, key);
if (fr.entry_index >= 0) {
_J2(MAP_PROC,_erase)(h, fr);
}
}
gb_inline void _J2(MAP_PROC,clear)(MAP_NAME *h) {
array_clear(&h->hashes);
array_clear(&h->entries);
}
#if 1
MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key) {
isize i = _J2(MAP_PROC,_find)(h, key).entry_index;
if (i < 0) {
return NULL;
}
return &h->entries.e[i];
}
MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) {
isize i = e->next;
while (i >= 0) {
if (hash_key_equal(h->entries.e[i].key, e->key)) {
return &h->entries.e[i];
}
i = h->entries.e[i].next;
}
return NULL;
}
isize _J2(MAP_PROC,multi_count)(MAP_NAME *h, HashKey key) {
isize count = 0;
MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key);
while (e != NULL) {
count++;
e = _J2(MAP_PROC,multi_find_next)(h, e);
}
return count;
}
void _J2(MAP_PROC,multi_get_all)(MAP_NAME *h, HashKey key, MAP_TYPE *items) {
isize i = 0;
MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key);
while (e != NULL) {
items[i++] = e->value;
e = _J2(MAP_PROC,multi_find_next)(h, e);
}
}
void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
MapFindResult fr;
isize i;
if (h->hashes.count == 0) {
_J2(MAP_PROC,grow)(h);
}
// Make
fr = _J2(MAP_PROC,_find)(h, key);
i = _J2(MAP_PROC,_add_entry)(h, key);
if (fr.entry_prev < 0) {
h->hashes.e[fr.hash_index] = i;
} else {
h->entries.e[fr.entry_prev].next = i;
}
h->entries.e[i].next = fr.entry_index;
h->entries.e[i].value = value;
// Grow if needed
if (_J2(MAP_PROC,_full)(h)) {
_J2(MAP_PROC,grow)(h);
}
}
void _J2(MAP_PROC,multi_remove)(MAP_NAME *h, HashKey key, MAP_ENTRY *e) {
MapFindResult fr = _J2(MAP_PROC,_find_from_entry)(h, e);
if (fr.entry_index >= 0) {
_J2(MAP_PROC,_erase)(h, fr);
}
}
void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key) {
while (_J2(MAP_PROC,get)(h, key) != NULL) {
_J2(MAP_PROC,remove)(h, key);
}
}
#endif
#undef _J2
#undef MAP_TYPE
#undef MAP_PROC
#undef MAP_NAME
#undef MAP_ENTRY
+381
View File
@@ -0,0 +1,381 @@
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
// NOTE(bill): This util stuff is the same for every `Map`
struct MapFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
enum HashKeyKind {
HashKey_Default,
HashKey_String,
HashKey_Ptr,
HashKey_PtrAndId,
};
struct PtrAndId {
void *ptr;
u32 id;
};
struct HashKey {
HashKeyKind kind;
// u128 key;
u64 key;
union {
String string; // if String, s.len > 0
void * ptr;
PtrAndId ptr_and_id;
};
};
gb_inline HashKey hashing_proc(void const *data, isize len) {
HashKey h = {HashKey_Default};
h.kind = HashKey_Default;
// h.key = u128_from_u64(gb_fnv64a(data, len));
h.key = gb_fnv64a(data, len);
return h;
}
gb_inline HashKey hash_string(String s) {
HashKey h = hashing_proc(s.text, s.len);
h.kind = HashKey_String;
h.string = s;
return h;
}
gb_inline HashKey hash_pointer(void *ptr) {
HashKey h = {HashKey_Ptr};
h.key = cast(u64)cast(uintptr)ptr;
h.ptr = ptr;
return h;
}
gb_inline HashKey hash_ptr_and_id(void *ptr, u32 id) {
HashKey h = {HashKey_PtrAndId};
h.key = cast(u64)cast(uintptr)ptr;
h.ptr_and_id.ptr = ptr;
h.ptr_and_id.id = id;
return h;
}
bool hash_key_equal(HashKey a, HashKey b) {
if (a.key == b.key) {
// NOTE(bill): If two string's hashes collide, compare the strings themselves
if (a.kind == HashKey_String) {
if (b.kind == HashKey_String) {
return a.string == b.string;
}
return false;
} else if (a.kind == HashKey_PtrAndId) {
if (b.kind == HashKey_PtrAndId) {
return a.ptr_and_id.id == b.ptr_and_id.id;
}
return false;
}
return true;
}
return false;
}
bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); }
bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); }
#endif
template <typename T>
struct MapEntry {
HashKey key;
isize next;
T value;
};
template <typename T>
struct Map {
Array<isize> hashes;
Array<MapEntry<T> > entries;
};
template <typename T> void map_init (Map<T> *h, gbAllocator a);
template <typename T> void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity);
template <typename T> void map_destroy (Map<T> *h);
template <typename T> T * map_get (Map<T> *h, HashKey key);
template <typename T> void map_set (Map<T> *h, HashKey key, T const &value);
template <typename T> void map_remove (Map<T> *h, HashKey key);
template <typename T> void map_clear (Map<T> *h);
template <typename T> void map_grow (Map<T> *h);
template <typename T> void map_rehash (Map<T> *h, isize new_count);
// Mutlivalued map procedure
template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey key);
template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
template <typename T> isize multi_map_count (Map<T> *h, HashKey key);
template <typename T> void multi_map_get_all (Map<T> *h, HashKey key, T *items);
template <typename T> void multi_map_insert (Map<T> *h, HashKey key, T const &value);
template <typename T> void multi_map_remove (Map<T> *h, HashKey key, MapEntry<T> *e);
template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key);
template <typename T>
gb_inline void map_init(Map<T> *h, gbAllocator a) {
array_init(&h->hashes, a);
array_init(&h->entries, a);
}
template <typename T>
gb_inline void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity) {
array_init(&h->hashes, a, capacity);
array_init(&h->entries, a, capacity);
}
template <typename T>
gb_inline void map_destroy(Map<T> *h) {
array_free(&h->entries);
array_free(&h->hashes);
}
template <typename T>
gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
MapEntry<T> e = {};
e.key = key;
e.next = -1;
array_add(&h->entries, e);
return h->entries.count-1;
}
template <typename T>
gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(h->hashes.count));
fr.hash_index = key.key % h->hashes.count;
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(h->entries[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal MapFindResult map__find_from_entry(Map<T> *h, MapEntry<T> *e) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
fr.hash_index = e->key.key % h->hashes.count;
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (&h->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal b32 map__full(Map<T> *h) {
return 0.75f * h->hashes.count <= h->entries.count;
}
template <typename T>
gb_inline void map_grow(Map<T> *h) {
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
map_rehash(h, new_count);
}
template <typename T>
void map_rehash(Map<T> *h, isize new_count) {
isize i, j;
Map<T> nh = {};
map_init(&nh, h->hashes.allocator);
array_resize(&nh.hashes, new_count);
array_reserve(&nh.entries, h->entries.count);
for (i = 0; i < new_count; i++) {
nh.hashes[i] = -1;
}
for (i = 0; i < h->entries.count; i++) {
MapEntry<T> *e = &h->entries[i];
MapFindResult fr;
if (nh.hashes.count == 0) {
map_grow(&nh);
}
fr = map__find(&nh, e->key);
j = map__add_entry(&nh, e->key);
if (fr.entry_prev < 0) {
nh.hashes[fr.hash_index] = j;
} else {
nh.entries[fr.entry_prev].next = j;
}
nh.entries[j].next = fr.entry_index;
nh.entries[j].value = e->value;
if (map__full(&nh)) {
map_grow(&nh);
}
}
map_destroy(h);
*h = nh;
}
template <typename T>
gb_inline T *map_get(Map<T> *h, HashKey key) {
isize index = map__find(h, key).entry_index;
if (index >= 0) {
return &h->entries[index].value;
}
return nullptr;
}
template <typename T>
void map_set(Map<T> *h, HashKey key, T const &value) {
isize index;
MapFindResult fr;
if (h->hashes.count == 0)
map_grow(h);
fr = map__find(h, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = map__add_entry(h, key);
if (fr.entry_prev >= 0) {
h->entries[fr.entry_prev].next = index;
} else {
h->hashes[fr.hash_index] = index;
}
}
h->entries[index].value = value;
if (map__full(h)) {
map_grow(h);
}
}
template <typename T>
void map__erase(Map<T> *h, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev < 0) {
h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
} else {
h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
return;
}
h->entries[fr.entry_index] = h->entries[h->entries.count-1];
last = map__find(h, h->entries[fr.entry_index].key);
if (last.entry_prev >= 0) {
h->entries[last.entry_prev].next = fr.entry_index;
} else {
h->hashes[last.hash_index] = fr.entry_index;
}
}
template <typename T>
void map_remove(Map<T> *h, HashKey key) {
MapFindResult fr = map__find(h, key);
if (fr.entry_index >= 0) {
map__erase(h, fr);
}
}
template <typename T>
gb_inline void map_clear(Map<T> *h) {
array_clear(&h->hashes);
array_clear(&h->entries);
}
#if 1
template <typename T>
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
isize i = map__find(h, key).entry_index;
if (i < 0) {
return nullptr;
}
return &h->entries[i];
}
template <typename T>
MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
isize i = e->next;
while (i >= 0) {
if (hash_key_equal(h->entries[i].key, e->key)) {
return &h->entries[i];
}
i = h->entries[i].next;
}
return nullptr;
}
template <typename T>
isize multi_map_count(Map<T> *h, HashKey key) {
isize count = 0;
MapEntry<T> *e = multi_map_find_first(h, key);
while (e != nullptr) {
count++;
e = multi_map_find_next(h, e);
}
return count;
}
template <typename T>
void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
isize i = 0;
MapEntry<T> *e = multi_map_find_first(h, key);
while (e != nullptr) {
items[i++] = e->value;
e = multi_map_find_next(h, e);
}
}
template <typename T>
void multi_map_insert(Map<T> *h, HashKey key, T const &value) {
MapFindResult fr;
isize i;
if (h->hashes.count == 0) {
map_grow(h);
}
// Make
fr = map__find(h, key);
i = map__add_entry(h, key);
if (fr.entry_prev < 0) {
h->hashes[fr.hash_index] = i;
} else {
h->entries[fr.entry_prev].next = i;
}
h->entries[i].next = fr.entry_index;
h->entries[i].value = value;
// Grow if needed
if (map__full(h)) {
map_grow(h);
}
}
template <typename T>
void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
MapFindResult fr = map__find_from_entry(h, e);
if (fr.entry_index >= 0) {
map__erase(h, fr);
}
}
template <typename T>
void multi_map_remove_all(Map<T> *h, HashKey key) {
while (map_get(h, key) != nullptr) {
map_remove(h, key);
}
}
#endif
+225
View File
@@ -0,0 +1,225 @@
//-----------------------------------------------------------------------------
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
// Note - The x86 and x64 versions do _not_ produce the same results, as the
// algorithms are optimized for their respective platforms. You can still
// compile and run any of them on any platform, but your performance with the
// non-native version will be less than optimal.
#if defined(_MSC_VER)
#define ROTL32(x,y) _rotl(x,y)
#define ROTL64(x,y) _rotl64(x,y)
#else
gb_inline u32 rotl32(u32 x, i8 r) {
return (x << r) | (x >> (32-r));
}
gb_inline u64 rotl64(u64 x, i8 r) {
return (x << r) | (x >> (64-r));
}
#define ROTL32(x,y) rotl32(x,y)
#define ROTL64(x,y) rotl64(x,y)
#endif
gb_inline u32 fmix32(u32 h) {
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
gb_inline u64 fmix64(u64 k) {
k ^= k >> 33;
k *= 0xff51afd7ed558ccdULL;
k ^= k >> 33;
k *= 0xc4ceb9fe1a85ec53ULL;
k ^= k >> 33;
return k;
}
gb_inline u32 mm3_getblock32(u32 const *p, isize i) {
return p[i];
}
gb_inline u64 mm3_getblock64(u64 const *p, isize i) {
return p[i];
}
void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) {
u8 const * data = cast(u8 const *)key;
isize nblocks = len / 16;
u64 h1 = seed;
u64 h2 = seed;
u64 const c1 = 0x87c37b91114253d5ULL;
u64 const c2 = 0x4cf5ad432745937fULL;
u64 const * blocks = cast(u64 const *)data;
for (isize i = 0; i < nblocks; i++) {
u64 k1 = mm3_getblock64(blocks, i*2 + 0);
u64 k2 = mm3_getblock64(blocks, i*2 + 1);
k1 *= c1; k1 = ROTL64(k1, 31); k1 *= c2; h1 ^= k1;
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
}
u8 const * tail = cast(u8 const *)(data + nblocks*16);
u64 k1 = 0;
u64 k2 = 0;
switch(len & 15) {
case 15: k2 ^= ((u64)tail[14]) << 48;
case 14: k2 ^= ((u64)tail[13]) << 40;
case 13: k2 ^= ((u64)tail[12]) << 32;
case 12: k2 ^= ((u64)tail[11]) << 24;
case 11: k2 ^= ((u64)tail[10]) << 16;
case 10: k2 ^= ((u64)tail[ 9]) << 8;
case 9: k2 ^= ((u64)tail[ 8]) << 0;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
case 8: k1 ^= ((u64)tail[ 7]) << 56;
case 7: k1 ^= ((u64)tail[ 6]) << 48;
case 6: k1 ^= ((u64)tail[ 5]) << 40;
case 5: k1 ^= ((u64)tail[ 4]) << 32;
case 4: k1 ^= ((u64)tail[ 3]) << 24;
case 3: k1 ^= ((u64)tail[ 2]) << 16;
case 2: k1 ^= ((u64)tail[ 1]) << 8;
case 1: k1 ^= ((u64)tail[ 0]) << 0;
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
}
h1 ^= len;
h2 ^= len;
h1 += h2;
h2 += h1;
h1 = fmix64(h1);
h2 = fmix64(h2);
h1 += h2;
h2 += h1;
((u64 *)out)[0] = h1;
((u64 *)out)[1] = h2;
}
void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) {
u8 const * data = cast(u8 * const)key;
isize nblocks = len / 16;
u32 h1 = seed;
u32 h2 = seed;
u32 h3 = seed;
u32 h4 = seed;
u32 const c1 = 0x239b961b;
u32 const c2 = 0xab0e9789;
u32 const c3 = 0x38b34ae5;
u32 const c4 = 0xa1e38b93;
//----------
// body
u32 const * blocks = cast(u32 const *)(data + nblocks*16);
for (isize i = -nblocks; i != 0; i++) {
u32 k1 = mm3_getblock32(blocks, i*4 + 0);
u32 k2 = mm3_getblock32(blocks, i*4 + 1);
u32 k3 = mm3_getblock32(blocks, i*4 + 2);
u32 k4 = mm3_getblock32(blocks, i*4 + 3);
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
}
//----------
// tail
u8 const * tail = cast(u8 const *)(data + nblocks*16);
u32 k1 = 0;
u32 k2 = 0;
u32 k3 = 0;
u32 k4 = 0;
switch(len & 15) {
case 15: k4 ^= tail[14] << 16;
case 14: k4 ^= tail[13] << 8;
case 13: k4 ^= tail[12] << 0;
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
case 12: k3 ^= tail[11] << 24;
case 11: k3 ^= tail[10] << 16;
case 10: k3 ^= tail[ 9] << 8;
case 9: k3 ^= tail[ 8] << 0;
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
case 8: k2 ^= tail[ 7] << 24;
case 7: k2 ^= tail[ 6] << 16;
case 6: k2 ^= tail[ 5] << 8;
case 5: k2 ^= tail[ 4] << 0;
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
case 4: k1 ^= tail[ 3] << 24;
case 3: k1 ^= tail[ 2] << 16;
case 2: k1 ^= tail[ 1] << 8;
case 1: k1 ^= tail[ 0] << 0;
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
h1 = fmix32(h1);
h2 = fmix32(h2);
h3 = fmix32(h3);
h4 = fmix32(h4);
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
((u32 *)out)[0] = h1;
((u32 *)out)[1] = h2;
((u32 *)out)[2] = h3;
((u32 *)out)[3] = h4;
}
gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
u128 res;
#if defined(GB_ARCH_64_BIT)
MurmurHash3_x64_128(key, len, seed, &res);
#else
MurmurHash3_x86_128(key, len, seed, &res);
#endif
return res;
}
-1305
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@ gb_inline void print_indent(isize indent) {
} }
void print_ast(AstNode *node, isize indent) { void print_ast(AstNode *node, isize indent) {
if (node == NULL) if (node == nullptr)
return; return;
switch (node->kind) { switch (node->kind) {
+271 -338
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -267,7 +267,6 @@ enum ssaOp {
SSA_OPS SSA_OPS
#undef SSA_OP #undef SSA_OP
}; };
typedef enum ssaOp ssaOp;
String const ssa_op_strings[] = { String const ssa_op_strings[] = {
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1}, #define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
+120 -56
View File
@@ -1,29 +1,51 @@
gb_global gbArena string_buffer_arena = {0}; gb_global gbArena string_buffer_arena = {};
gb_global gbAllocator string_buffer_allocator = {0}; gb_global gbAllocator string_buffer_allocator = {};
gb_global gbMutex string_buffer_mutex = {};
void init_string_buffer_memory(void) { void init_string_buffer_memory(void) {
// NOTE(bill): This should be enough memory for file systems // NOTE(bill): This should be enough memory for file systems
gb_arena_init_from_allocator(&string_buffer_arena, heap_allocator(), gb_megabytes(1)); gb_arena_init_from_allocator(&string_buffer_arena, heap_allocator(), gb_megabytes(1));
string_buffer_allocator = gb_arena_allocator(&string_buffer_arena); string_buffer_allocator = gb_arena_allocator(&string_buffer_arena);
gb_mutex_init(&string_buffer_mutex);
} }
// NOTE(bill): Used for UTF-8 strings // NOTE(bill): Used for UTF-8 strings
typedef struct String { struct String {
u8 * text; u8 * text;
isize len; isize len;
} String;
u8 &operator[](isize i) {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
u8 const &operator[](isize i) const {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
};
// NOTE(bill): used for printf style arguments // NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text #define LIT(x) ((int)(x).len), (x).text
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1} #define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1} #if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
#else
#define str_lit(c_str) String{cast(u8 *)c_str, gb_size_of(c_str)-1}
#endif
// NOTE(bill): String16 is only used for Windows due to its file directories // NOTE(bill): String16 is only used for Windows due to its file directories
typedef struct String16 { struct String16 {
wchar_t *text; wchar_t *text;
isize len; isize len;
} String16; wchar_t &operator[](isize i) {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
wchar_t const &operator[](isize i) const {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
};
gb_inline String make_string(u8 *text, isize len) { gb_inline String make_string(u8 *text, isize len) {
@@ -44,11 +66,29 @@ gb_inline String16 make_string16(wchar_t *text, isize len) {
return s; return s;
} }
isize string16_len(wchar_t *s) {
if (s == nullptr) {
return 0;
}
wchar_t *p = s;
while (*p) {
p++;
}
return p - s;
}
gb_inline String make_string_c(char *text) { gb_inline String make_string_c(char *text) {
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text)); return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
} }
String substring(String s, isize lo, isize hi) {
isize max = s.len;
GB_ASSERT(lo <= hi && hi <= max);
return make_string(s.text+lo, hi-lo);
}
@@ -56,8 +96,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
if (a.len == b.len) { if (a.len == b.len) {
isize i; isize i;
for (i = 0; i < a.len; i++) { for (i = 0; i < a.len; i++) {
char x = cast(char)a.text[i]; char x = cast(char)a[i];
char y = cast(char)b.text[i]; char y = cast(char)b[i];
if (gb_char_to_lower(x) != gb_char_to_lower(y)) if (gb_char_to_lower(x) != gb_char_to_lower(y))
return false; return false;
} }
@@ -66,9 +106,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
return false; return false;
} }
int string_compare(String x, String y) { int string_compare(String const &x, String const &y) {
if (!(x.len == y.len && if (x.len != y.len || x.text != y.text) {
x.text == y.text)) {
isize n, fast, offset, curr_block; isize n, fast, offset, curr_block;
isize *la, *lb; isize *la, *lb;
isize pos; isize pos;
@@ -88,16 +127,16 @@ int string_compare(String x, String y) {
for (; curr_block < fast; curr_block++) { for (; curr_block < fast; curr_block++) {
if (la[curr_block] ^ lb[curr_block]) { if (la[curr_block] ^ lb[curr_block]) {
for (pos = curr_block*gb_size_of(isize); pos < n; pos++) { for (pos = curr_block*gb_size_of(isize); pos < n; pos++) {
if (x.text[pos] ^ y.text[pos]) { if (x[pos] ^ y[pos]) {
return cast(int)x.text[pos] - cast(int)y.text[pos]; return cast(int)x[pos] - cast(int)y[pos];
} }
} }
} }
} }
for (; offset < n; offset++) { for (; offset < n; offset++) {
if (x.text[offset] ^ y.text[offset]) { if (x[offset] ^ y[offset]) {
return cast(int)x.text[offset] - cast(int)y.text[offset]; return cast(int)x[offset] - cast(int)y[offset];
} }
} }
} }
@@ -110,12 +149,36 @@ GB_COMPARE_PROC(string_cmp_proc) {
return string_compare(x, y); return string_compare(x, y);
} }
gb_inline bool str_eq(String a, String b) { return a.len == b.len ? gb_memcompare(a.text, b.text, a.len) == 0 : false; } gb_inline bool str_eq(String const &a, String const &b) {
gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); } if (a.len != b.len) return false;
gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; } for (isize i = 0; i < a.len; i++) {
gb_inline bool str_gt(String a, String b) { return string_compare(a, b) > 0; } if (a.text[i] != b.text[i]) {
gb_inline bool str_le(String a, String b) { return string_compare(a, b) <= 0; } return false;
gb_inline bool str_ge(String a, String b) { return string_compare(a, b) >= 0; } }
}
return true;
}
gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b); }
gb_inline bool str_lt(String const &a, String const &b) { return string_compare(a, b) < 0; }
gb_inline bool str_gt(String const &a, String const &b) { return string_compare(a, b) > 0; }
gb_inline bool str_le(String const &a, String const &b) { return string_compare(a, b) <= 0; }
gb_inline bool str_ge(String const &a, String const &b) { return string_compare(a, b) >= 0; }
gb_inline bool operator == (String const &a, String const &b) { return str_eq(a, b); }
gb_inline bool operator != (String const &a, String const &b) { return str_ne(a, b); }
gb_inline bool operator < (String const &a, String const &b) { return str_lt(a, b); }
gb_inline bool operator > (String const &a, String const &b) { return str_gt(a, b); }
gb_inline bool operator <= (String const &a, String const &b) { return str_le(a, b); }
gb_inline bool operator >= (String const &a, String const &b) { return str_ge(a, b); }
template <isize N> bool operator == (String const &a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator != (String const &a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator < (String const &a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator > (String const &a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator <= (String const &a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator >= (String const &a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
gb_inline bool str_has_prefix(String s, String prefix) { gb_inline bool str_has_prefix(String s, String prefix) {
isize i; isize i;
@@ -123,7 +186,7 @@ gb_inline bool str_has_prefix(String s, String prefix) {
return false; return false;
} }
for (i = 0; i < prefix.len; i++) { for (i = 0; i < prefix.len; i++) {
if (s.text[i] != prefix.text[i]) { if (s[i] != prefix[i]) {
return false; return false;
} }
} }
@@ -133,11 +196,10 @@ gb_inline bool str_has_prefix(String s, String prefix) {
gb_inline isize string_extension_position(String str) { gb_inline isize string_extension_position(String str) {
isize dot_pos = -1; isize dot_pos = -1;
isize i = str.len; isize i = str.len;
bool seen_dot = false;
while (i --> 0) { while (i --> 0) {
if (str.text[i] == GB_PATH_SEPARATOR) if (str[i] == GB_PATH_SEPARATOR)
break; break;
if (str.text[i] == '.') { if (str[i] == '.') {
dot_pos = i; dot_pos = i;
break; break;
} }
@@ -147,11 +209,11 @@ gb_inline isize string_extension_position(String str) {
} }
String string_trim_whitespace(String str) { String string_trim_whitespace(String str) {
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) { while (str.len > 0 && rune_is_whitespace(str[str.len-1])) {
str.len--; str.len--;
} }
while (str.len > 0 && rune_is_whitespace(str.text[0])) { while (str.len > 0 && rune_is_whitespace(str[0])) {
str.text++; str.text++;
str.len--; str.len--;
} }
@@ -166,7 +228,7 @@ gb_inline bool string_has_extension(String str, String ext) {
} }
isize len = str.len; isize len = str.len;
for (isize i = len-1; i >= 0; i--) { for (isize i = len-1; i >= 0; i--) {
if (str.text[i] == '.') { if (str[i] == '.') {
break; break;
} }
len--; len--;
@@ -182,7 +244,7 @@ gb_inline bool string_has_extension(String str, String ext) {
bool string_contains_char(String s, u8 c) { bool string_contains_char(String s, u8 c) {
isize i; isize i;
for (i = 0; i < s.len; i++) { for (i = 0; i < s.len; i++) {
if (s.text[i] == c) if (s[i] == c)
return true; return true;
} }
return false; return false;
@@ -194,15 +256,15 @@ String filename_from_path(String s) {
isize j = 0; isize j = 0;
s.len = i; s.len = i;
for (j = i-1; j >= 0; j--) { for (j = i-1; j >= 0; j--) {
if (s.text[j] == '/' || if (s[j] == '/' ||
s.text[j] == '\\') { s[j] == '\\') {
break; break;
} }
} }
s.text += j+1; s.text += j+1;
s.len = i-j-1; s.len = i-j-1;
} }
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
@@ -217,7 +279,7 @@ String filename_from_path(String s) {
return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size); return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
} }
int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) { int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) {
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL); return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr);
} }
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
@@ -251,45 +313,47 @@ String16 string_to_string16(gbAllocator a, String s) {
wchar_t *text; wchar_t *text;
if (s.len < 1) { if (s.len < 1) {
return make_string16(NULL, 0); return make_string16(nullptr, 0);
} }
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0); len = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, nullptr, 0);
if (len == 0) { if (len == 0) {
return make_string16(NULL, 0); return make_string16(nullptr, 0);
} }
text = gb_alloc_array(a, wchar_t, len+1); text = gb_alloc_array(a, wchar_t, len+1);
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len); len1 = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, text, cast(int)len);
if (len1 == 0) { if (len1 == 0) {
gb_free(a, text); gb_free(a, text);
return make_string16(NULL, 0); return make_string16(nullptr, 0);
} }
text[len] = 0; text[len] = 0;
return make_string16(text, len-1); return make_string16(text, len-1);
} }
String string16_to_string(gbAllocator a, String16 s) { String string16_to_string(gbAllocator a, String16 s) {
int len, len1; int len, len1;
u8 *text; u8 *text;
if (s.len < 1) { if (s.len < 1) {
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0); len = convert_widechar_to_multibyte(s.text, cast(int)s.len, nullptr, 0);
if (len == 0) { if (len == 0) {
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
len += 1; // NOTE(bill): It needs an extra 1 for some reason
text = gb_alloc_array(a, u8, len+1); text = gb_alloc_array(a, u8, len+1);
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len); len1 = convert_widechar_to_multibyte(s.text, cast(int)s.len, cast(char *)text, cast(int)len);
if (len1 == 0) { if (len1 == 0) {
gb_free(a, text); gb_free(a, text);
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
text[len] = 0; text[len] = 0;
@@ -315,18 +379,18 @@ String string16_to_string(gbAllocator a, String16 s) {
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) { bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
u8 c; u8 c;
if (s.text[0] == quote && if (s[0] == quote &&
(quote == '\'' || quote == '"')) { (quote == '\'' || quote == '"')) {
return false; return false;
} else if (s.text[0] >= 0x80) { } else if (s[0] >= 0x80) {
Rune r = -1; Rune r = -1;
isize size = gb_utf8_decode(s.text, s.len, &r); isize size = gb_utf8_decode(s.text, s.len, &r);
*rune = r; *rune = r;
*multiple_bytes = true; *multiple_bytes = true;
*tail_string = make_string(s.text+size, s.len-size); *tail_string = make_string(s.text+size, s.len-size);
return true; return true;
} else if (s.text[0] != '\\') { } else if (s[0] != '\\') {
*rune = s.text[0]; *rune = s[0];
*tail_string = make_string(s.text+1, s.len-1); *tail_string = make_string(s.text+1, s.len-1);
return true; return true;
} }
@@ -334,7 +398,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
if (s.len <= 1) { if (s.len <= 1) {
return false; return false;
} }
c = s.text[1]; c = s[1];
s = make_string(s.text+2, s.len-2); s = make_string(s.text+2, s.len-2);
switch (c) { switch (c) {
@@ -372,7 +436,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
return false; return false;
} }
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
i32 d = gb_digit_to_int(s.text[i]); i32 d = gb_digit_to_int(s[i]);
if (d < 0 || d > 7) { if (d < 0 || d > 7) {
return false; return false;
} }
@@ -400,7 +464,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
return false; return false;
} }
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
i32 d = gb_hex_digit_to_int(s.text[i]); i32 d = gb_hex_digit_to_int(s[i]);
if (d < 0) { if (d < 0) {
return false; return false;
} }
@@ -433,8 +497,8 @@ i32 unquote_string(gbAllocator a, String *s_) {
if (n < 2) { if (n < 2) {
return 0; return 0;
} }
quote = s.text[0]; quote = s[0];
if (quote != s.text[n-1]) { if (quote != s[n-1]) {
return 0; return 0;
} }
s.text += 1; s.text += 1;
@@ -471,12 +535,12 @@ i32 unquote_string(gbAllocator a, String *s_) {
{ {
u8 rune_temp[4] = {0}; u8 rune_temp[4] = {};
isize buf_len = 3*s.len / 2; isize buf_len = 3*s.len / 2;
u8 *buf = gb_alloc_array(a, u8, buf_len); u8 *buf = gb_alloc_array(a, u8, buf_len);
isize offset = 0; isize offset = 0;
while (s.len > 0) { while (s.len > 0) {
String tail_string = {0}; String tail_string = {};
Rune r = 0; Rune r = 0;
bool multiple_bytes = false; bool multiple_bytes = false;
bool success = unquote_char(s, quote, &r, &multiple_bytes, &tail_string); bool success = unquote_char(s, quote, &r, &multiple_bytes, &tail_string);
+27 -22
View File
@@ -1,14 +1,15 @@
typedef struct TimeStamp { struct TimeStamp {
u64 start; u64 start;
u64 finish; u64 finish;
String label; String label;
} TimeStamp; };
typedef struct Timings { struct Timings {
TimeStamp total; TimeStamp total;
Array(TimeStamp) sections; Array<TimeStamp> sections;
u64 freq; u64 freq;
} Timings; f64 total_time_seconds;
};
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
@@ -45,13 +46,7 @@ u64 unix_time_stamp__freq(void) {
if (freq == 0) { if (freq == 0) {
struct timespec ts; struct timespec ts;
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts); clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
// that would be an absurd resolution (or lack thereof)
GB_ASSERT(ts.tv_sec == 0);
freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0); freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0);
GB_ASSERT(freq != 0);
} }
return freq; return freq;
@@ -89,7 +84,7 @@ TimeStamp make_time_stamp(String label) {
} }
void timings_init(Timings *t, String label, isize buffer_size) { void timings_init(Timings *t, String label, isize buffer_size) {
array_init_reserve(&t->sections, heap_allocator(), buffer_size); array_init(&t->sections, heap_allocator(), buffer_size);
t->total = make_time_stamp(label); t->total = make_time_stamp(label);
t->freq = time_stamp__freq(); t->freq = time_stamp__freq();
} }
@@ -100,7 +95,7 @@ void timings_destroy(Timings *t) {
void timings__stop_current_section(Timings *t) { void timings__stop_current_section(Timings *t) {
if (t->sections.count > 0) { if (t->sections.count > 0) {
t->sections.e[t->sections.count-1].finish = time_stamp_time_now(); t->sections[t->sections.count-1].finish = time_stamp_time_now();
} }
} }
@@ -109,36 +104,46 @@ void timings_start_section(Timings *t, String label) {
array_add(&t->sections, make_time_stamp(label)); array_add(&t->sections, make_time_stamp(label));
} }
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) { f64 time_stamp_as_second(TimeStamp ts, u64 freq) {
GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label)); GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label));
return 1000.0 * cast(f64)(ts.finish - ts.start) / cast(f64)freq; return cast(f64)(ts.finish - ts.start) / cast(f64)freq;
}
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
return 1000.0*time_stamp_as_second(ts, freq);
} }
void timings_print_all(Timings *t) { void timings_print_all(Timings *t) {
char const SPACES[] = " "; char const SPACES[] = " ";
isize max_len, i; isize max_len;
timings__stop_current_section(t); timings__stop_current_section(t);
t->total.finish = time_stamp_time_now(); t->total.finish = time_stamp_time_now();
max_len = t->total.label.len; max_len = t->total.label.len;
for_array(i, t->sections) { for_array(i, t->sections) {
TimeStamp ts = t->sections.e[i]; TimeStamp ts = t->sections[i];
max_len = gb_max(max_len, ts.label.len); max_len = gb_max(max_len, ts.label.len);
} }
GB_ASSERT(max_len <= gb_size_of(SPACES)-1); GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
gb_printf("%.*s%.*s - %.3f ms\n", t->total_time_seconds = time_stamp_as_second(t->total, t->freq);
f64 total_ms = time_stamp_as_ms(t->total, t->freq);
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
LIT(t->total.label), LIT(t->total.label),
cast(int)(max_len-t->total.label.len), SPACES, cast(int)(max_len-t->total.label.len), SPACES,
time_stamp_as_ms(t->total, t->freq)); total_ms,
cast(f64)100.0);
for_array(i, t->sections) { for_array(i, t->sections) {
TimeStamp ts = t->sections.e[i]; TimeStamp ts = t->sections[i];
gb_printf("%.*s%.*s - %.3f ms\n", f64 section_ms = time_stamp_as_ms(ts, t->freq);
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
LIT(ts.label), LIT(ts.label),
cast(int)(max_len-ts.label.len), SPACES, cast(int)(max_len-ts.label.len), SPACES,
time_stamp_as_ms(ts, t->freq)); section_ms, 100*section_ms/total_ms);
} }
} }
+144 -91
View File
@@ -25,6 +25,7 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_Mul, "*"), \ TOKEN_KIND(Token_Mul, "*"), \
TOKEN_KIND(Token_Quo, "/"), \ TOKEN_KIND(Token_Quo, "/"), \
TOKEN_KIND(Token_Mod, "%"), \ TOKEN_KIND(Token_Mod, "%"), \
TOKEN_KIND(Token_ModMod, "%%"), \
TOKEN_KIND(Token_And, "&"), \ TOKEN_KIND(Token_And, "&"), \
TOKEN_KIND(Token_Or, "|"), \ TOKEN_KIND(Token_Or, "|"), \
TOKEN_KIND(Token_Xor, "~"), \ TOKEN_KIND(Token_Xor, "~"), \
@@ -36,24 +37,27 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_CmpOr, "||"), \ TOKEN_KIND(Token_CmpOr, "||"), \
\ \
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
TOKEN_KIND(Token_AddEq, "+="), \ TOKEN_KIND(Token_AddEq, "+="), \
TOKEN_KIND(Token_SubEq, "-="), \ TOKEN_KIND(Token_SubEq, "-="), \
TOKEN_KIND(Token_MulEq, "*="), \ TOKEN_KIND(Token_MulEq, "*="), \
TOKEN_KIND(Token_QuoEq, "/="), \ TOKEN_KIND(Token_QuoEq, "/="), \
TOKEN_KIND(Token_ModEq, "%="), \ TOKEN_KIND(Token_ModEq, "%="), \
TOKEN_KIND(Token_AndEq, "&="), \ TOKEN_KIND(Token_ModModEq, "%%="), \
TOKEN_KIND(Token_OrEq, "|="), \ TOKEN_KIND(Token_AndEq, "&="), \
TOKEN_KIND(Token_XorEq, "~="), \ TOKEN_KIND(Token_OrEq, "|="), \
TOKEN_KIND(Token_AndNotEq, "&~="), \ TOKEN_KIND(Token_XorEq, "~="), \
TOKEN_KIND(Token_ShlEq, "<<="), \ TOKEN_KIND(Token_AndNotEq, "&~="), \
TOKEN_KIND(Token_ShrEq, ">>="), \ TOKEN_KIND(Token_ShlEq, "<<="), \
TOKEN_KIND(Token_CmpAndEq, "&&="), \ TOKEN_KIND(Token_ShrEq, ">>="), \
TOKEN_KIND(Token_CmpOrEq, "||="), \ TOKEN_KIND(Token_CmpAndEq, "&&="), \
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ TOKEN_KIND(Token_CmpOrEq, "||="), \
TOKEN_KIND(Token_ArrowRight, "->"), \ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
TOKEN_KIND(Token_ArrowLeft, "<-"), \ TOKEN_KIND(Token_ArrowRight, "->"), \
TOKEN_KIND(Token_Inc, "++"), \ TOKEN_KIND(Token_ArrowLeft, "<-"), \
TOKEN_KIND(Token_Dec, "--"), \ TOKEN_KIND(Token_DoubleArrowRight, "=>"), \
/* TOKEN_KIND(Token_Inc, "++"), */ \
/* TOKEN_KIND(Token_Dec, "--"), */ \
TOKEN_KIND(Token_Undef, "---"), \
\ \
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_CmpEq, "=="), \ TOKEN_KIND(Token_CmpEq, "=="), \
@@ -74,54 +78,63 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token_Semicolon, ";"), \ TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \ TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \ TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \ TOKEN_KIND(Token_Ellipsis, "..."), \
TOKEN_KIND(Token_HalfClosed, "..<"), \ TOKEN_KIND(Token_HalfClosed, ".."), \
TOKEN_KIND(Token_BackSlash, "\\"), \ TOKEN_KIND(Token_BackSlash, "\\"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\ \
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_when, "when"), \ TOKEN_KIND(Token_import, "import"), \
TOKEN_KIND(Token_if, "if"), \ TOKEN_KIND(Token_import_load, "import_load"), \
TOKEN_KIND(Token_else, "else"), \ TOKEN_KIND(Token_foreign, "foreign"), \
TOKEN_KIND(Token_for, "for"), \ TOKEN_KIND(Token_foreign_library, "foreign_library"), \
TOKEN_KIND(Token_in, "in"), \ TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
TOKEN_KIND(Token_match, "match"), \ TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_default, "default"), \ TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_case, "case"), \ TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_break, "break"), \ TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_continue, "continue"), \ TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \ TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_defer, "defer"), \ TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_return, "return"), \ TOKEN_KIND(Token_do, "do"), \
TOKEN_KIND(Token_give, "give"), \ TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_proc, "proc"), \ TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_macro, "macro"), \ TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_struct, "struct"), \ TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_union, "union"), \ TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \ TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_bit_field, "bit_field"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \ TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_immutable, "immutable"), \ TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_context, "context"), \ TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \ TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_yield, "yield"), \ TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_await, "await"), \ TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_atomic, "atomic"), \ TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_size_of, "size_of"), \
TOKEN_KIND(Token_align_of, "align_of"), \
TOKEN_KIND(Token_offset_of, "offset_of"), \
TOKEN_KIND(Token_type_of, "type_of"), \
TOKEN_KIND(Token_type_info_of, "type_info_of"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_yield, "yield"), \
TOKEN_KIND(Token_await, "await"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "") TOKEN_KIND(Token_Count, "")
typedef enum TokenKind { enum TokenKind {
#define TOKEN_KIND(e, s) e #define TOKEN_KIND(e, s) e
TOKEN_KINDS TOKEN_KINDS
#undef TOKEN_KIND #undef TOKEN_KIND
} TokenKind; };
String const token_strings[] = { String const token_strings[] = {
#define TOKEN_KIND(e, s) {cast(u8 *)s, gb_size_of(s)-1} #define TOKEN_KIND(e, s) {cast(u8 *)s, gb_size_of(s)-1}
@@ -130,11 +143,11 @@ String const token_strings[] = {
}; };
typedef struct TokenPos { struct TokenPos {
String file; String file;
isize line; isize line;
isize column; isize column;
} TokenPos; };
i32 token_pos_cmp(TokenPos a, TokenPos b) { i32 token_pos_cmp(TokenPos a, TokenPos b) {
if (a.line == b.line) { if (a.line == b.line) {
@@ -152,11 +165,11 @@ bool token_pos_eq(TokenPos a, TokenPos b) {
return token_pos_cmp(a, b) == 0; return token_pos_cmp(a, b) == 0;
} }
typedef struct Token { struct Token {
TokenKind kind; TokenKind kind;
String string; String string;
TokenPos pos; TokenPos pos;
} Token; };
Token empty_token = {Token_Invalid}; Token empty_token = {Token_Invalid};
Token blank_token = {Token_Ident, {cast(u8 *)"_", 1}}; Token blank_token = {Token_Ident, {cast(u8 *)"_", 1}};
@@ -167,12 +180,12 @@ Token make_token_ident(String s) {
} }
typedef struct ErrorCollector { struct ErrorCollector {
TokenPos prev; TokenPos prev;
i64 count; i64 count;
i64 warning_count; i64 warning_count;
gbMutex mutex; gbMutex mutex;
} ErrorCollector; };
gb_global ErrorCollector global_error_collector; gb_global ErrorCollector global_error_collector;
@@ -306,7 +319,7 @@ gb_inline bool token_is_shift(TokenKind t) {
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); } gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
typedef enum TokenizerInitError { enum TokenizerInitError {
TokenizerInit_None, TokenizerInit_None,
TokenizerInit_Invalid, TokenizerInit_Invalid,
@@ -315,18 +328,18 @@ typedef enum TokenizerInitError {
TokenizerInit_Empty, TokenizerInit_Empty,
TokenizerInit_Count, TokenizerInit_Count,
} TokenizerInitError; };
typedef struct TokenizerState { struct TokenizerState {
Rune curr_rune; // current character Rune curr_rune; // current character
u8 * curr; // character pos u8 * curr; // character pos
u8 * read_curr; // pos from start u8 * read_curr; // pos from start
u8 * line; // current line pos u8 * line; // current line pos
isize line_count; isize line_count;
} TokenizerState; };
typedef struct Tokenizer { struct Tokenizer {
String fullpath; String fullpath;
u8 *start; u8 *start;
u8 *end; u8 *end;
@@ -338,12 +351,12 @@ typedef struct Tokenizer {
isize line_count; isize line_count;
isize error_count; isize error_count;
Array(String) allocated_strings; Array<String> allocated_strings;
} Tokenizer; };
TokenizerState save_tokenizer_state(Tokenizer *t) { TokenizerState save_tokenizer_state(Tokenizer *t) {
TokenizerState state = {0}; TokenizerState state = {};
state.curr_rune = t->curr_rune; state.curr_rune = t->curr_rune;
state.curr = t->curr; state.curr = t->curr;
state.read_curr = t->read_curr; state.read_curr = t->read_curr;
@@ -421,7 +434,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
// TODO(bill): Memory map rather than copy contents // TODO(bill): Memory map rather than copy contents
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str); gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
gb_zero_item(t); gb_zero_item(t);
if (fc.data != NULL) { if (fc.data != nullptr) {
t->start = cast(u8 *)fc.data; t->start = cast(u8 *)fc.data;
t->line = t->read_curr = t->curr = t->start; t->line = t->read_curr = t->curr = t->start;
t->end = t->start + fc.size; t->end = t->start + fc.size;
@@ -435,7 +448,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
array_init(&t->allocated_strings, heap_allocator()); array_init(&t->allocated_strings, heap_allocator());
} else { } else {
gbFile f = {0}; gbFile f = {};
gbFileError file_err = gb_file_open(&f, c_str); gbFileError file_err = gb_file_open(&f, c_str);
switch (file_err) { switch (file_err) {
@@ -456,11 +469,11 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
} }
gb_inline void destroy_tokenizer(Tokenizer *t) { gb_inline void destroy_tokenizer(Tokenizer *t) {
if (t->start != NULL) { if (t->start != nullptr) {
gb_free(heap_allocator(), t->start); gb_free(heap_allocator(), t->start);
} }
for_array(i, t->allocated_strings) { for_array(i, t->allocated_strings) {
gb_free(heap_allocator(), t->allocated_strings.e[i].text); gb_free(heap_allocator(), t->allocated_strings[i].text);
} }
array_free(&t->allocated_strings); array_free(&t->allocated_strings);
} }
@@ -492,7 +505,7 @@ gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
} }
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) { Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
Token token = {0}; Token token = {};
token.kind = Token_Integer; token.kind = Token_Integer;
token.string = make_string(t->curr, 1); token.string = make_string(t->curr, 1);
token.pos.file = t->fullpath; token.pos.file = t->fullpath;
@@ -538,7 +551,14 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
if (t->curr - prev <= 2) { if (t->curr - prev <= 2) {
token.kind = Token_Invalid; token.kind = Token_Invalid;
} }
} else { } /* else if (t->curr_rune == 'h') { // Hexadecimal Float
token.kind = Token_Float;
advance_to_next_rune(t);
scan_mantissa(t, 16);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} */ else {
seen_decimal_point = false; seen_decimal_point = false;
scan_mantissa(t, 10); scan_mantissa(t, 10);
@@ -578,11 +598,9 @@ exponent:
scan_mantissa(t, 10); scan_mantissa(t, 10);
} }
switch (t->curr_rune) { if (t->curr_rune == 'i') {
case 'i': case 'j': case 'k':
token.kind = Token_Imag; token.kind = Token_Imag;
advance_to_next_rune(t); advance_to_next_rune(t);
break;
} }
end: end:
@@ -744,7 +762,7 @@ bool tokenizer_find_line_end(Tokenizer *t) {
Token tokenizer_get_token(Tokenizer *t) { Token tokenizer_get_token(Tokenizer *t) {
tokenizer_skip_whitespace(t); tokenizer_skip_whitespace(t);
Token token = {0}; Token token = {};
token.string = make_string(t->curr, 1); token.string = make_string(t->curr, 1);
token.pos.file = t->fullpath; token.pos.file = t->fullpath;
token.pos.line = t->line_count; token.pos.line = t->line_count;
@@ -762,7 +780,7 @@ Token tokenizer_get_token(Tokenizer *t) {
// NOTE(bill): All keywords are > 1 // NOTE(bill): All keywords are > 1
if (token.string.len > 1) { if (token.string.len > 1) {
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
if (str_eq(token.string, token_strings[k])) { if (token.string == token_strings[k]) {
token.kind = cast(TokenKind)k; token.kind = cast(TokenKind)k;
break; break;
} }
@@ -868,10 +886,10 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = Token_Period; // Default token.kind = Token_Period; // Default
if (t->curr_rune == '.') { // Could be an ellipsis if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_Ellipsis; token.kind = Token_HalfClosed;
if (t->curr_rune == '<') { if (t->curr_rune == '.') {
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_HalfClosed; token.kind = Token_Ellipsis;
} }
} }
break; break;
@@ -892,13 +910,45 @@ Token tokenizer_get_token(Tokenizer *t) {
case '}': token.kind = Token_CloseBrace; break; case '}': token.kind = Token_CloseBrace; break;
case '\\': token.kind = Token_BackSlash; break; case '\\': token.kind = Token_BackSlash; break;
case 0x2260: token.kind = Token_NotEq; break; // '≠'
case 0x2264: token.kind = Token_LtEq; break; // '≤'
case 0x2265: token.kind = Token_GtEq; break; // '≥'
case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; case '=':
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; token.kind = Token_Eq;
if (t->curr_rune == '>') {
advance_to_next_rune(t);
token.kind = Token_DoubleArrowRight;
} else if (t->curr_rune == '=') {
advance_to_next_rune(t);
token.kind = Token_CmpEq;
}
break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break; // case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break; case '+': token.kind = token_kind_variant2(t, Token_Add, Token_AddEq); break;
case '-':
token.kind = Token_Sub;
if (t->curr_rune == '=') {
advance_to_next_rune(t);
token.kind = Token_SubEq;
} else if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_Invalid;
if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_Undef;
}
} else if (t->curr_rune == '>') {
advance_to_next_rune(t);
token.kind = Token_ArrowRight;
}
break;
case '/': { case '/': {
if (t->curr_rune == '/') { if (t->curr_rune == '/') {
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) { while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
@@ -909,7 +959,9 @@ Token tokenizer_get_token(Tokenizer *t) {
isize comment_scope = 1; isize comment_scope = 1;
advance_to_next_rune(t); advance_to_next_rune(t);
while (comment_scope > 0) { while (comment_scope > 0) {
if (t->curr_rune == '/') { if (t->curr_rune == GB_RUNE_EOF) {
break;
} else if (t->curr_rune == '/') {
advance_to_next_rune(t); advance_to_next_rune(t);
if (t->curr_rune == '*') { if (t->curr_rune == '*') {
advance_to_next_rune(t); advance_to_next_rune(t);
@@ -933,6 +985,7 @@ Token tokenizer_get_token(Tokenizer *t) {
case '<': case '<':
if (t->curr_rune == '-') { if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_ArrowLeft; token.kind = Token_ArrowLeft;
} else { } else {
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
@@ -957,8 +1010,8 @@ Token tokenizer_get_token(Tokenizer *t) {
case '|': token.kind = token_kind_dub_eq(t, '|', Token_Or, Token_OrEq, Token_CmpOr, Token_CmpOrEq); break; case '|': token.kind = token_kind_dub_eq(t, '|', Token_Or, Token_OrEq, Token_CmpOr, Token_CmpOrEq); break;
default: default:
if (curr_rune != GB_RUNE_BOM) { if (curr_rune != GB_RUNE_BOM) {
u8 str[4] = {0}; u8 str[4] = {};
int len = cast(int)gb_utf8_encode_rune(str, curr_rune); int len = cast(int)gb_utf8_encode_rune(str, curr_rune);
tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune); tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune);
} }
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,9 +1,10 @@
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4245) #pragma warning(disable: 4245)
extern "C" {
// #include "utf8proc/utf8proc.h" // #include "utf8proc/utf8proc.h"
#include "utf8proc/utf8proc.c" #include "utf8proc/utf8proc.c"
}
#pragma warning(pop) #pragma warning(pop)
+8 -12
View File
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
} }
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) { UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
return utf8proc_get_property(c)->category; return cast(utf8proc_category_t)utf8proc_get_property(c)->category;
} }
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) { UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
@@ -393,15 +393,15 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
#define utf8proc_decompose_lump(replacement_uc) \ #define utf8proc_decompose_lump(replacement_uc) \
return utf8proc_decompose_char((replacement_uc), dst, bufsize, \ return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
options & ~UTF8PROC_LUMP, last_boundclass) (utf8proc_option_t)(options & ~UTF8PROC_LUMP), last_boundclass)
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) { UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
const utf8proc_property_t *property; const utf8proc_property_t *property;
utf8proc_propval_t category; utf8proc_category_t category;
utf8proc_int32_t hangul_sindex; utf8proc_int32_t hangul_sindex;
if (uc < 0 || uc >= 0x110000) return UTF8PROC_ERROR_NOTASSIGNED; if (uc < 0 || uc >= 0x110000) return UTF8PROC_ERROR_NOTASSIGNED;
property = unsafe_get_property(uc); property = unsafe_get_property(uc);
category = property->category; category = cast(utf8proc_category_t)property->category;
hangul_sindex = uc - UTF8PROC_HANGUL_SBASE; hangul_sindex = uc - UTF8PROC_HANGUL_SBASE;
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) { if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) {
@@ -728,28 +728,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_DECOMPOSE));
UTF8PROC_DECOMPOSE);
return retval; return retval;
} }
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_COMPOSE));
UTF8PROC_COMPOSE);
return retval; return retval;
} }
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_DECOMPOSE|UTF8PROC_COMPAT));
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
return retval; return retval;
} }
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) { UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval; utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_COMPOSE|UTF8PROC_COMPAT));
UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
return retval; return retval;
} }