mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-17 21:21:04 +00:00
Merge branch 'master' into bill/rexcode
This commit is contained in:
@@ -143,7 +143,7 @@ derive :: proc(
|
||||
m_ := 4 * u64(p) * (m / u64(4 * p))
|
||||
b := mem.alloc_bytes_non_zeroed(
|
||||
int(m_) * BLOCK_SIZE_BYTES,
|
||||
alignment = mem.DEFAULT_PAGE_SIZE,
|
||||
alignment = mem.PAGE_SIZE,
|
||||
allocator = allocator,
|
||||
) or_return
|
||||
defer delete(b, allocator)
|
||||
|
||||
89
core/encoding/json/unparse.odin
Normal file
89
core/encoding/json/unparse.odin
Normal file
@@ -0,0 +1,89 @@
|
||||
package encoding_json
|
||||
|
||||
import "base:runtime"
|
||||
import "core:strings"
|
||||
import "core:io"
|
||||
import "core:slice"
|
||||
|
||||
Unparse_Error :: union #shared_nil {
|
||||
io.Error,
|
||||
runtime.Allocator_Error,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
unparse :: proc(v: Value, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: string, err: Unparse_Error) {
|
||||
b := strings.builder_make(allocator, loc)
|
||||
defer if err != nil {
|
||||
strings.builder_destroy(&b)
|
||||
}
|
||||
|
||||
// temp guard in case we are sorting map keys, which will use temp allocations
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
|
||||
|
||||
opt := opt
|
||||
unparse_to_builder(&b, v, &opt) or_return
|
||||
data = string(b.buf[:])
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
unparse_to_builder :: proc(b: ^strings.Builder, v: Value, opt: ^Marshal_Options) -> Unparse_Error {
|
||||
return unparse_to_writer(strings.to_writer(b), v, opt)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
unparse_to_writer :: proc(w: io.Writer, value: Value, opt: ^Marshal_Options) -> Unparse_Error {
|
||||
switch v in value {
|
||||
case nil, Null:
|
||||
io.write_string(w, "null") or_return
|
||||
case Integer:
|
||||
base := 16 if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) else 10
|
||||
io.write_i64(w, v, base) or_return
|
||||
case Float:
|
||||
io.write_f64(w, v) or_return
|
||||
case Boolean:
|
||||
io.write_string(w, "true" if v else "false") or_return
|
||||
case String:
|
||||
io.write_quoted_string(w, v, '"', nil, true) or_return
|
||||
case Array:
|
||||
opt_write_start(w, opt, '[') or_return
|
||||
for e, i in v {
|
||||
opt_write_iteration(w, opt, i == 0) or_return
|
||||
unparse_to_writer (w, e, opt) or_return
|
||||
}
|
||||
opt_write_end(w, opt, ']') or_return
|
||||
case Object:
|
||||
if !opt.sort_maps_by_key {
|
||||
opt_write_start(w, opt, '{') or_return
|
||||
for first_iteration := true; key, val in v {
|
||||
opt_write_iteration(w, opt, first_iteration) or_return
|
||||
opt_write_key (w, opt, key) or_return
|
||||
unparse_to_writer (w, val, opt) or_return
|
||||
first_iteration = false
|
||||
}
|
||||
opt_write_end(w, opt, '}') or_return
|
||||
} else {
|
||||
Map_Entry :: struct {
|
||||
key: string,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
entries := make([dynamic]Map_Entry, 0, len(v), context.temp_allocator) or_return
|
||||
for key, val in v {
|
||||
_, _ = append(&entries, Map_Entry{key, val})
|
||||
}
|
||||
|
||||
slice.sort_by(entries[:], proc(i, j: Map_Entry) -> bool { return i.key < j.key })
|
||||
|
||||
opt_write_start(w, opt, '{') or_return
|
||||
for e, i in entries {
|
||||
opt_write_iteration(w, opt, i == 0) or_return
|
||||
opt_write_key (w, opt, e.key) or_return
|
||||
unparse_to_writer (w, e.value, opt) or_return
|
||||
}
|
||||
opt_write_end(w, opt, '}') or_return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -11,13 +11,21 @@ Command-Line Syntax:
|
||||
Arguments are treated differently depending on how they're formatted.
|
||||
The format is similar to the Odin binary's way of handling compiler flags.
|
||||
|
||||
type handling
|
||||
------------ ------------------------
|
||||
<positional> depends on struct layout
|
||||
-<flag> set a bool true
|
||||
-<flag:option> set flag to option
|
||||
-<flag=option> set flag to option, alternative syntax
|
||||
-<map>:<key>=<value> set map[key] to value
|
||||
type handling
|
||||
------------ ------------------------
|
||||
<positional> depends on struct layout
|
||||
-<flag> set a bool true
|
||||
-<flag:option> set flag to option
|
||||
-<flag=option> set flag to option, alternative syntax
|
||||
-<flag:option1,opt...> set bit_set flag to one or more options
|
||||
-<flag=option1,opt...> set bit_set flag to one or more options, alternative syntax
|
||||
-<map>:<key>=<value> set map[key] to value
|
||||
|
||||
Underscores (`_`) in a flag will be replaced with dashes (`-`).
|
||||
|
||||
Bit sets may be set with a strictly comma-separated list of options.
|
||||
|
||||
Bit sets may also be set with a binary string of 0s and 1s, and will be parsed from left to right, from least significant bit to most significant bit. Underscores are allowed and will be ignored. However, starting with an underscore is disallowed.
|
||||
|
||||
|
||||
Unhandled Arguments:
|
||||
|
||||
@@ -20,6 +20,14 @@ Optimization_Level :: enum {
|
||||
Ludicrous_Speed,
|
||||
}
|
||||
|
||||
Vet_Flag :: enum {
|
||||
Unused,
|
||||
Unused_Variables,
|
||||
Unused_Imports,
|
||||
Shadowing,
|
||||
Using_Stmt,
|
||||
}
|
||||
|
||||
// It's simple but powerful.
|
||||
my_custom_type_setter :: proc(
|
||||
data: rawptr,
|
||||
@@ -83,6 +91,8 @@ main :: proc() {
|
||||
schedule: datetime.DateTime `usage:"Launch tasks at this time."`,
|
||||
|
||||
opt: Optimization_Level `usage:"Optimization level."`,
|
||||
vet_flags: bit_set[Vet_Flag] `usage:"Vet flags. Example usage:
|
||||
-vet-flags:Unused,Shadowing"`,
|
||||
todo: [dynamic]string `usage:"Todo items."`,
|
||||
|
||||
accuracy: Fixed_Point1_1 `args:"required" usage:"Lenience in FLOP calculations."`,
|
||||
|
||||
@@ -110,7 +110,7 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
|
||||
case f32be: (^f32be)(ptr)^ = cast(f32be) value
|
||||
case f64be: (^f64be)(ptr)^ = cast(f64be) value
|
||||
}
|
||||
|
||||
|
||||
case runtime.Type_Info_Complex:
|
||||
value := strconv.parse_complex128(str) or_return
|
||||
switch type_info.id {
|
||||
@@ -118,7 +118,7 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
|
||||
case complex64: (^complex64) (ptr)^ = (complex64)(value)
|
||||
case complex128: (^complex128)(ptr)^ = value
|
||||
}
|
||||
|
||||
|
||||
case runtime.Type_Info_Quaternion:
|
||||
value := strconv.parse_quaternion256(str) or_return
|
||||
switch type_info.id {
|
||||
@@ -152,15 +152,16 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
// Parse a string of 1's and 0's, from left to right,
|
||||
// Parse a string of 1s and 0s, from left to right,
|
||||
// least significant bit to most significant bit.
|
||||
value: u128
|
||||
|
||||
// NOTE: `upper` is inclusive, i.e: `0..=31`
|
||||
max_bit_index := u128(1 + specific_type_info.upper - specific_type_info.lower)
|
||||
underscores := u128(strings.count(str, "_"))
|
||||
bit_index_limit := u128(1 + specific_type_info.upper - specific_type_info.lower) + underscores
|
||||
bit_index := u128(0)
|
||||
#no_bounds_check for string_index in 0..<uint(len(str)) {
|
||||
if bit_index == max_bit_index {
|
||||
if bit_index == bit_index_limit {
|
||||
// The string's too long for this bit_set.
|
||||
return false
|
||||
}
|
||||
@@ -421,7 +422,7 @@ parse_and_set_pointer_by_type :: proc(ptr: rawptr, str: string, type_info: ^runt
|
||||
}
|
||||
} else {
|
||||
parse_and_set_pointer_by_named_type(ptr, str, type_info.id, arg_tag, &error)
|
||||
|
||||
|
||||
if error != nil {
|
||||
// So far, it's none of the types that we recognize.
|
||||
// Check to see if we can set it by base type, if allowed.
|
||||
@@ -471,6 +472,70 @@ parse_and_set_pointer_by_type :: proc(ptr: rawptr, str: string, type_info: ^runt
|
||||
}
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
if str[0] == '0' || str[0] == '1' {
|
||||
if !parse_and_set_pointer_by_base_type(ptr, str, type_info) {
|
||||
return Parse_Error {
|
||||
// The caller will add more details.
|
||||
.Bad_Value,
|
||||
"",
|
||||
}
|
||||
} else {
|
||||
error = nil
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
value: u128
|
||||
|
||||
et := runtime.type_info_base(specific_type_info.elem)
|
||||
if enum_type_info, is_enum := et.variant.(runtime.Type_Info_Enum); is_enum {
|
||||
names, _ := strings.split(str, ",", context.temp_allocator)
|
||||
valid_names := enum_type_info.names
|
||||
underlying_values := enum_type_info.values
|
||||
|
||||
#no_bounds_check outer_loop: for name in names {
|
||||
found: bool
|
||||
#no_bounds_check for valid_name, index in valid_names {
|
||||
if name == valid_name {
|
||||
shift := u128(underlying_values[index]) - u128(specific_type_info.lower)
|
||||
value |= u128(1 << shift)
|
||||
found = true
|
||||
continue outer_loop
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return Parse_Error {
|
||||
.Bad_Value,
|
||||
fmt.tprintf(
|
||||
"Invalid value name: `%s`. Valid names are: %s",
|
||||
name,
|
||||
valid_names,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Parse_Error {
|
||||
// The caller will add more details.
|
||||
.Bad_Value,
|
||||
"",
|
||||
}
|
||||
}
|
||||
|
||||
if specific_type_info.underlying != nil {
|
||||
set_unbounded_integer_by_type(ptr, value, specific_type_info.underlying.id)
|
||||
} else {
|
||||
switch 8*type_info.size {
|
||||
case 8: (^u8) (ptr)^ = cast(u8) value
|
||||
case 16: (^u16) (ptr)^ = cast(u16) value
|
||||
case 32: (^u32) (ptr)^ = cast(u32) value
|
||||
case 64: (^u64) (ptr)^ = cast(u64) value
|
||||
case 128: (^u128)(ptr)^ = value
|
||||
}
|
||||
}
|
||||
error = nil
|
||||
|
||||
case:
|
||||
if type_info.id == ^os.File {
|
||||
parse_and_set_pointer_by_named_type(ptr, str, type_info.id, arg_tag, &error)
|
||||
|
||||
68
core/log/doc.odin
Normal file
68
core/log/doc.odin
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Implementation of logging facilities.
|
||||
|
||||
Odin has builtin support for logging using procedure `context`. After a logger is created it can then be assigned to
|
||||
`context.logger` and used implicitly in future log calls.
|
||||
|
||||
While it is ok for simple apps to use the `core:fmt` package, libraries and complex apps should prefer the `core:log`
|
||||
package. By using the implicit logger library and application authors allow the caller to decide how to process log
|
||||
messages.
|
||||
|
||||
When starting out you can easily just init the logger with a single line.
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import "core:log"
|
||||
|
||||
main :: proc() {
|
||||
context.logger = log.create_console_logger()
|
||||
log.info("Hello World!")
|
||||
}
|
||||
|
||||
However when the application gets more involved you might want to try a more complex setup.
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import "core:log"
|
||||
import "core:os"
|
||||
|
||||
main :: proc() {
|
||||
handle, err := os.open("logs.txt", os.O_RDWR | os.O_APPEND | os.O_CREATE, 0o666)
|
||||
assert(err == nil, "Cannot open log file")
|
||||
|
||||
file_logger := log.create_file_logger(handle)
|
||||
// This closes the file handle
|
||||
defer log.destroy_file_logger(file_logger)
|
||||
|
||||
console_logger := log.create_console_logger()
|
||||
defer log.destroy_console_logger(console_logger)
|
||||
|
||||
multi_logger := log.create_multi_logger(console_logger, file_logger)
|
||||
defer log.destroy_multi_logger(multi_logger)
|
||||
|
||||
context.logger = multi_logger
|
||||
|
||||
log.info("Application started!")
|
||||
}
|
||||
|
||||
It is also possible to create an allocator that logs all allocations.
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import "core:log"
|
||||
|
||||
main :: proc() {
|
||||
context.logger = log.create_console_logger()
|
||||
|
||||
alloc: log.Log_Allocator
|
||||
log.log_allocator_init(&alloc, .Debug)
|
||||
context.allocator = log.log_allocator(&alloc)
|
||||
|
||||
a := new(i32)
|
||||
free(a)
|
||||
}
|
||||
*/
|
||||
package log
|
||||
@@ -11,6 +11,7 @@ import "core:terminal"
|
||||
import "core:terminal/ansi"
|
||||
import "core:time"
|
||||
|
||||
// Strings to output when `.Level` is included in the logger options.
|
||||
Level_Headers := [?]string{
|
||||
0..<10 = "[DEBUG] --- ",
|
||||
10..<20 = "[INFO ] --- ",
|
||||
@@ -19,22 +20,49 @@ Level_Headers := [?]string{
|
||||
40..<50 = "[FATAL] --- ",
|
||||
}
|
||||
|
||||
/*
|
||||
The default option set for a console logger.
|
||||
|
||||
It is similar to the file logger default option set, but the output includes colors.
|
||||
|
||||
When you use this set of options you can expect the following output:
|
||||
|
||||
[LEVEL] --- [YYYY-MM-DD HH:MM:SS] [file.odin:L:proc()] Message
|
||||
|
||||
For example:
|
||||
|
||||
[INFO ] --- [2025-01-02 12:34:56] [main.odin:8:main()] Hello World!
|
||||
*/
|
||||
Default_Console_Logger_Opts :: Options{
|
||||
.Level,
|
||||
.Terminal_Color,
|
||||
.Short_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
} | Full_Timestamp_Opts
|
||||
} + Full_Timestamp_Opts
|
||||
|
||||
/*
|
||||
The default option set for a file logger.
|
||||
|
||||
It is similar to the console logger default option set, but the output is not colored.
|
||||
|
||||
When you use this set of options you can expect the following output:
|
||||
|
||||
[LEVEL] --- [YYYY-MM-DD HH:MM:SS] [file.odin:L:proc()] Message
|
||||
|
||||
For example:
|
||||
|
||||
[INFO ] --- [2025-01-02 12:34:56] [main.odin:8:main()] Hello World!
|
||||
*/
|
||||
Default_File_Logger_Opts :: Options{
|
||||
.Level,
|
||||
.Short_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
} | Full_Timestamp_Opts
|
||||
} + Full_Timestamp_Opts
|
||||
|
||||
|
||||
//Data backing a file or console logger.
|
||||
File_Console_Logger_Data :: struct {
|
||||
file_handle: ^os.File,
|
||||
ident: string,
|
||||
@@ -67,6 +95,21 @@ init_standard_stream_status :: proc "contextless" () {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Create a logger that outputs to a file.
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
When no longer needed can be destroyed with `destroy_file_logger`.
|
||||
|
||||
Inputs:
|
||||
- `h`: A handle to the output file
|
||||
- `lowest`: Log level to use (default is `.Debug`)
|
||||
- `opt`: Specifies additional data present in the log output (default is `log.Default_File_Logger_Opts`)
|
||||
- `ident`: Identifier to include in the output (default is `""`)
|
||||
- `allocator`: Allocator to use for data backing the logger (default is `context.allocator`)
|
||||
*/
|
||||
create_file_logger :: proc(f: ^os.File, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
|
||||
data := new(File_Console_Logger_Data, allocator)
|
||||
data.file_handle = f
|
||||
@@ -74,6 +117,13 @@ create_file_logger :: proc(f: ^os.File, lowest := Level.Debug, opt := Default_Fi
|
||||
return Logger{file_logger_proc, data, lowest, opt}
|
||||
}
|
||||
|
||||
/*
|
||||
Free the state allocated with `create_file_logger` and close the file handle.
|
||||
|
||||
Inputs:
|
||||
- `log`: Logger created with `create_file_logger`
|
||||
- `allocator`: Allocator passed to `create_file_logger` (default is `context.allocator`)
|
||||
*/
|
||||
destroy_file_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
data := cast(^File_Console_Logger_Data)log.data
|
||||
if data.file_handle != nil {
|
||||
@@ -82,6 +132,19 @@ destroy_file_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
free(data, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Create a logger that outputs to the terminal.
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
When no longer needed can be destroyed with `destroy_console_logger`.
|
||||
|
||||
Inputs:
|
||||
- `lowest`: Log level to use (default is `.Debug`)
|
||||
- `opt`: Specifies additional data present in the log output (default is `log.Default_Console_Logger_Opts`)
|
||||
- `ident`: Identifier to include in the output (default is `""`)
|
||||
- `allocator`: Allocator to use for data backing the logger (default is `context.allocator`)
|
||||
*/
|
||||
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
|
||||
data := new(File_Console_Logger_Data, allocator)
|
||||
data.file_handle = nil
|
||||
@@ -89,6 +152,13 @@ create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logg
|
||||
return Logger{console_logger_proc, data, lowest, opt}
|
||||
}
|
||||
|
||||
/*
|
||||
Free the state allocated with `create_console_logger`.
|
||||
|
||||
Inputs:
|
||||
- `log`: Logger created with `create_console_logger`
|
||||
- `allocator`: Allocator passed to `create_console_logger` (default is `context.allocator`)
|
||||
*/
|
||||
destroy_console_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
free(log.data, allocator)
|
||||
}
|
||||
@@ -117,6 +187,7 @@ _file_console_logger_proc :: proc(h: ^os.File, ident: string, level: Level, text
|
||||
fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text)
|
||||
}
|
||||
|
||||
|
||||
file_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
data := cast(^File_Console_Logger_Data)logger_data
|
||||
_file_console_logger_proc(data.file_handle, data.ident, level, text, options, location)
|
||||
@@ -136,6 +207,7 @@ console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, opt
|
||||
_file_console_logger_proc(h, data.ident, level, text, options, location)
|
||||
}
|
||||
|
||||
// Helper used to build the part of the message including the log level.
|
||||
do_level_header :: proc(opts: Options, str: ^strings.Builder, level: Level) {
|
||||
|
||||
RESET :: ansi.CSI + ansi.RESET + ansi.SGR
|
||||
@@ -162,6 +234,7 @@ do_level_header :: proc(opts: Options, str: ^strings.Builder, level: Level) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper used to build the part of the message including the data and time.
|
||||
do_time_header :: proc(opts: Options, buf: ^strings.Builder, t: time.Time) {
|
||||
when time.IS_SUPPORTED {
|
||||
if Full_Timestamp_Opts & opts != nil {
|
||||
@@ -180,6 +253,7 @@ do_time_header :: proc(opts: Options, buf: ^strings.Builder, t: time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper used to build the part of the message including the file location.
|
||||
do_location_header :: proc(opts: Options, buf: ^strings.Builder, location := #caller_location) {
|
||||
if Location_Header_Opts & opts == nil {
|
||||
return
|
||||
|
||||
@@ -1,52 +1,102 @@
|
||||
// Implementations of the `context.Logger` interface.
|
||||
package log
|
||||
|
||||
import "base:runtime"
|
||||
import "core:fmt"
|
||||
|
||||
|
||||
// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
|
||||
//These are defined in package `base:runtime` as they are used in the `context`. This is to prevent an import definition cycle.
|
||||
|
||||
/*
|
||||
Logger_Level :: enum {
|
||||
Debug = 0,
|
||||
Info = 10,
|
||||
Warning = 20,
|
||||
Error = 30,
|
||||
Fatal = 40,
|
||||
}
|
||||
Logger_Level :: enum {
|
||||
Debug = 0,
|
||||
Info = 10,
|
||||
Warning = 20,
|
||||
Error = 30,
|
||||
Fatal = 40,
|
||||
}
|
||||
*/
|
||||
Level :: runtime.Logger_Level
|
||||
|
||||
/*
|
||||
Option :: enum {
|
||||
Level,
|
||||
Date,
|
||||
Time,
|
||||
Short_File_Path,
|
||||
Long_File_Path,
|
||||
Line,
|
||||
Procedure,
|
||||
Terminal_Color
|
||||
}
|
||||
Specifies additional data present in the log output.
|
||||
|
||||
Defined in `package runtime` as it is used in the `context`. This is to prevent an import definition cycle.
|
||||
|
||||
Option :: enum {
|
||||
// The log level, e.g. "[DEBUG] ---"
|
||||
Level,
|
||||
// The date, e.g. [2025-01-02]
|
||||
Date,
|
||||
// The time, e.g. [12:34:56]
|
||||
Time,
|
||||
// Just the filename, e.g. [main.odin]
|
||||
Short_File_Path,
|
||||
// Full file path, e.g. [/tmp/project/main.odin]
|
||||
Long_File_Path,
|
||||
// File line of the log statement, e.g. [8]
|
||||
Line,
|
||||
// Calling procedure, e.g. [main()]
|
||||
Procedure,
|
||||
// Enables colored output
|
||||
Terminal_Color
|
||||
}
|
||||
*/
|
||||
Option :: runtime.Logger_Option
|
||||
|
||||
/*
|
||||
Options :: bit_set[Option];
|
||||
Specifies additional data present in the log output.
|
||||
|
||||
Defined in `package runtime` as it is used in the `context`. This is to prevent an import definition cycle.
|
||||
|
||||
Options :: bit_set[Option];
|
||||
*/
|
||||
Options :: runtime.Logger_Options
|
||||
|
||||
/*
|
||||
A preset option set for a logger.
|
||||
|
||||
When you use this set of options you can expect the following output:
|
||||
|
||||
[YYYY-MM-DD HH:MM:SS] Message
|
||||
|
||||
For example:
|
||||
|
||||
[2025-01-02 12:34:56] Hello World!
|
||||
*/
|
||||
Full_Timestamp_Opts :: Options{
|
||||
.Date,
|
||||
.Time,
|
||||
}
|
||||
|
||||
/*
|
||||
A preset option set for a logger.
|
||||
|
||||
When you use this set of options you can expect the following output:
|
||||
|
||||
[file.odin:L:proc()] Message
|
||||
|
||||
For example:
|
||||
|
||||
[main.odin:8:main()] Hello World!
|
||||
*/
|
||||
Location_Header_Opts :: Options{
|
||||
.Short_File_Path,
|
||||
.Long_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
}
|
||||
|
||||
/*
|
||||
A preset option set for a logger.
|
||||
|
||||
When you use this set of options you can expect the following output:
|
||||
|
||||
[file.odin] Message
|
||||
|
||||
For example:
|
||||
|
||||
[main.odin] Hello World!
|
||||
*/
|
||||
Location_File_Opts :: Options{
|
||||
.Short_File_Path,
|
||||
.Long_File_Path,
|
||||
@@ -54,67 +104,206 @@ Location_File_Opts :: Options{
|
||||
|
||||
|
||||
/*
|
||||
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
|
||||
Implementation of the logger.
|
||||
|
||||
Defined in `package runtime` as it is used in the `context`. This is to prevent an import definition cycle.
|
||||
|
||||
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
|
||||
|
||||
*/
|
||||
Logger_Proc :: runtime.Logger_Proc
|
||||
|
||||
/*
|
||||
Logger :: struct {
|
||||
procedure: Logger_Proc,
|
||||
data: rawptr,
|
||||
lowest_level: Level,
|
||||
options: Logger_Options,
|
||||
}
|
||||
Data backing the logger.
|
||||
|
||||
Defined in `package runtime` as it is used in the `context`. This is to prevent an import definition cycle.
|
||||
|
||||
Logger :: struct {
|
||||
// Implementation
|
||||
procedure: Logger_Proc,
|
||||
// Configuration data passed to the implementation
|
||||
data: rawptr,
|
||||
// Minimum level for messages passed to the implementation
|
||||
lowest_level: Level,
|
||||
// Additional data present in the log output
|
||||
options: Logger_Options,
|
||||
}
|
||||
*/
|
||||
Logger :: runtime.Logger
|
||||
|
||||
/*
|
||||
Do nothing.
|
||||
|
||||
Defined in `package runtime` as it is used in the `context`. This is to prevent an import definition cycle.
|
||||
*/
|
||||
nil_logger_proc :: runtime.default_logger_proc
|
||||
|
||||
/*
|
||||
Create a logger that does nothing.
|
||||
|
||||
Returns:
|
||||
- A logger that does nothing
|
||||
*/
|
||||
nil_logger :: proc() -> Logger {
|
||||
return Logger{nil_logger_proc, nil, Level.Debug, nil}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Log a formatted message at the `Debug` level.
|
||||
|
||||
Inputs:
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
|
||||
logf(.Debug, fmt_str, ..args, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a formatted message at the `Info` level.
|
||||
|
||||
Inputs:
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
infof :: proc(fmt_str: string, args: ..any, location := #caller_location) {
|
||||
logf(.Info, fmt_str, ..args, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a formatted message at the `Warn` level.
|
||||
|
||||
Inputs:
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
warnf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
|
||||
logf(.Warning, fmt_str, ..args, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a formatted message at the `Error` level.
|
||||
|
||||
Inputs:
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
errorf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
|
||||
logf(.Error, fmt_str, ..args, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a formatted message at the `Fatal` level.
|
||||
|
||||
Inputs:
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
fatalf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
|
||||
logf(.Fatal, fmt_str, ..args, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a message at the `Debug` level.
|
||||
|
||||
Inputs:
|
||||
- `args`: values to be concatenated into the output
|
||||
- `sep`: separator to use when concatenating (default is `" "`)
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
debug :: proc(args: ..any, sep := " ", location := #caller_location) {
|
||||
log(.Debug, ..args, sep=sep, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a message at the `Info` level.
|
||||
|
||||
Inputs:
|
||||
- `args`: values to be concatenated into the output
|
||||
- `sep`: separator to use when concatenating (default is `" "`)
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
info :: proc(args: ..any, sep := " ", location := #caller_location) {
|
||||
log(.Info, ..args, sep=sep, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a message at the `Warn` level.
|
||||
|
||||
Inputs:
|
||||
- `args`: values to be concatenated into the output
|
||||
- `sep`: separator to use when concatenating (default is `" "`)
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
warn :: proc(args: ..any, sep := " ", location := #caller_location) {
|
||||
log(.Warning, ..args, sep=sep, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a message at the `Error` level.
|
||||
|
||||
Inputs:
|
||||
- `args`: values to be concatenated into the output
|
||||
- `sep`: separator to use when concatenating (default is `" "`)
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
error :: proc(args: ..any, sep := " ", location := #caller_location) {
|
||||
log(.Error, ..args, sep=sep, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a message at the `Fatal` level.
|
||||
|
||||
Inputs:
|
||||
- `args`: values to be concatenated into the output
|
||||
- `sep`: separator to use when concatenating (default is `" "`)
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
fatal :: proc(args: ..any, sep := " ", location := #caller_location) {
|
||||
log(.Fatal, ..args, sep=sep, location=location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a message at the `Fatal` level and abort the program.
|
||||
|
||||
Inputs:
|
||||
- `args`: values to be concatenated into the output
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
panic :: proc(args: ..any, location := #caller_location) -> ! {
|
||||
log(.Fatal, ..args, location=location)
|
||||
runtime.panic("log.panic", location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a formatted message at the `Fatal` level and abort the program.
|
||||
|
||||
Inputs:
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
panicf :: proc(fmt_str: string, args: ..any, location := #caller_location) -> ! {
|
||||
logf(.Fatal, fmt_str, ..args, location=location)
|
||||
runtime.panic("log.panicf", location)
|
||||
}
|
||||
|
||||
/*
|
||||
When condition is `false` log a message at the `Fatal` level and abort the program.
|
||||
|
||||
Can be disabled using `ODIN_DISABLE_ASSERT`.
|
||||
|
||||
Inputs:
|
||||
- `condition`: A boolean to check
|
||||
- `message`: Message to log when condition is false (a default is provided)
|
||||
- `loc`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
|
||||
if !condition {
|
||||
@@ -131,6 +320,17 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc :=
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When condition is `false` log a formatted message at the `Fatal` level and abort the program.
|
||||
|
||||
Can be disabled using `ODIN_DISABLE_ASSERT`.
|
||||
|
||||
Inputs:
|
||||
- `condition`: A boolean to check
|
||||
- `fmt_str`: A format string to use when condition is false, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `loc`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
assertf :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_location) {
|
||||
if !condition {
|
||||
@@ -152,6 +352,16 @@ assertf :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_lo
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When condition is `false` log a message at the `Fatal` level and abort the program.
|
||||
|
||||
Unlike `assert` this procedure cannot be disabled with `ODIN_DISABLE_ASSERT` and will always execute.
|
||||
|
||||
Inputs:
|
||||
- `condition`: A boolean to check
|
||||
- `message`: Message to log when condition is false (a default is provided)
|
||||
- `loc`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
|
||||
if !condition {
|
||||
@(cold)
|
||||
@@ -167,6 +377,17 @@ ensure :: proc(condition: bool, message := #caller_expression(condition), loc :=
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When condition is `false` log a formatted message at the `Fatal` level and abort the program.
|
||||
|
||||
Unlike `assertf` this procedure cannot be disabled with `ODIN_DISABLE_ASSERT` and will always execute.
|
||||
|
||||
Inputs:
|
||||
- `condition`: A boolean to check
|
||||
- `fmt_str`: A format string to use when condition is false, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `loc`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
ensuref :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_location) {
|
||||
if !condition {
|
||||
@(cold)
|
||||
@@ -184,7 +405,15 @@ ensuref :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_lo
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Log a message at the desired level.
|
||||
|
||||
Inputs:
|
||||
- `level`: The level of the message
|
||||
- `args`: values to be concatenated into the output
|
||||
- `sep`: separator to use when concatenating (default is `" "`)
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location) {
|
||||
logger := context.logger
|
||||
if logger.procedure == nil || logger.procedure == nil_logger_proc {
|
||||
@@ -198,6 +427,15 @@ log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location)
|
||||
logger.procedure(logger.data, level, str, logger.options, location)
|
||||
}
|
||||
|
||||
/*
|
||||
Log a formatted message at the desired level.
|
||||
|
||||
Inputs:
|
||||
- `level`: The level of the message
|
||||
- `fmt_str`: A format string, e.g. `"a: %v, b: %v"
|
||||
- `args`: Arguments for the format string
|
||||
- `location`: Location of the caller (default is #caller_location)
|
||||
*/
|
||||
logf :: proc(level: Level, fmt_str: string, args: ..any, location := #caller_location) {
|
||||
logger := context.logger
|
||||
if logger.procedure == nil || logger.procedure == nil_logger_proc {
|
||||
|
||||
@@ -6,6 +6,7 @@ import "base:runtime"
|
||||
import "core:sync"
|
||||
|
||||
// Format to use when logging allocations.
|
||||
Log_Allocator_Format :: enum {
|
||||
Bytes, // Actual number of bytes.
|
||||
Human, // Bytes in human units like bytes, kibibytes, etc. as appropriate.
|
||||
}
|
||||
@@ -15,13 +16,23 @@ Log_Allocator_Format :: enum {
|
||||
// The format can be changed by setting the `size_fmt: Log_Allocator_Format` field to either `Bytes` or `Human`.
|
||||
Log_Allocator :: struct {
|
||||
allocator: runtime.Allocator, // Wrapped allocator
|
||||
level: Level,
|
||||
prefix: string,
|
||||
lock: sync.Mutex,
|
||||
level: Level, // Log Level used for allocations
|
||||
prefix: string, // Prefix to use in log messages
|
||||
lock: sync.Mutex,
|
||||
size_fmt: Log_Allocator_Format, // Format to use when logging allocations
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the backing data for the allocator that logs all allocations.
|
||||
|
||||
Inputs:
|
||||
- `la`: Pointer to the data structure to initialize
|
||||
- `level`: Log level to use for allocations
|
||||
- `size_fmt`: Format to use when logging allocations (default is `.Bytes`)
|
||||
- `allocator`: Wrapped allocator (default is `context.allocator`)
|
||||
- `prefix`: Prefix to use in log messages (default is `""`)
|
||||
*/
|
||||
log_allocator_init :: proc(la: ^Log_Allocator, level: Level, size_fmt := Log_Allocator_Format.Bytes,
|
||||
allocator := context.allocator, prefix := "") {
|
||||
la.allocator = allocator
|
||||
la.level = level
|
||||
@@ -31,7 +42,15 @@ log_allocator_init :: proc(la: ^Log_Allocator, level: Level, size_fmt := Log_All
|
||||
}
|
||||
|
||||
/*
|
||||
Create an allocator that logs all allocations.
|
||||
|
||||
Inputs:
|
||||
- `la`: Pointer to the data structure backing the allocator
|
||||
|
||||
Returns:
|
||||
- An allocator that logs all allocations
|
||||
*/
|
||||
log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
|
||||
return runtime.Allocator{
|
||||
procedure = log_allocator_proc,
|
||||
data = la,
|
||||
@@ -39,6 +58,7 @@ log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
|
||||
}
|
||||
|
||||
// Backing procedure for allocator that logs all allocations.
|
||||
log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
|
||||
la := (^Log_Allocator)(allocator_data)
|
||||
|
||||
@@ -1,10 +1,27 @@
|
||||
package log
|
||||
|
||||
|
||||
// A container backing for multiple loggers.
|
||||
Multi_Logger_Data :: struct {
|
||||
loggers: []Logger,
|
||||
}
|
||||
|
||||
/*
|
||||
Create a logger that logs to all backing loggers.
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
When no longer needed can be destroyed with `destroy_multi_logger`.
|
||||
|
||||
Note: Logs using a multi logger take both the multi logger and the backing loggers' log levels into account.
|
||||
|
||||
Inputs:
|
||||
- `logs` - Backing loggers passed as multiple arguments
|
||||
- `allocator` - An allocator used to allocate data to store backing loggers (default is `context.allocator`)
|
||||
|
||||
Returns:
|
||||
- A multi logger
|
||||
*/
|
||||
create_multi_logger :: proc(logs: ..Logger, allocator := context.allocator) -> Logger {
|
||||
data := new(Multi_Logger_Data, allocator)
|
||||
data.loggers = make([]Logger, len(logs), allocator)
|
||||
@@ -12,12 +29,20 @@ create_multi_logger :: proc(logs: ..Logger, allocator := context.allocator) -> L
|
||||
return Logger{multi_logger_proc, data, Level.Debug, nil}
|
||||
}
|
||||
|
||||
/*
|
||||
Free the state allocated with `create_multi_logger`.
|
||||
|
||||
Inputs:
|
||||
- `log`: Logger created with `create_multi_logger`
|
||||
- `allocator`: Allocator passed to `create_multi_logger` (default is `context.allocator`)
|
||||
*/
|
||||
destroy_multi_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
data := (^Multi_Logger_Data)(log.data)
|
||||
delete(data.loggers, allocator)
|
||||
free(data, allocator)
|
||||
}
|
||||
|
||||
// Backing procedure for the multi logger.
|
||||
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
||||
options: Options, location := #caller_location) {
|
||||
data := cast(^Multi_Logger_Data)logger_data
|
||||
|
||||
@@ -1613,17 +1613,11 @@ is_power_of_two :: proc "contextless" (x: int) -> bool {
|
||||
|
||||
@(require_results)
|
||||
next_power_of_two :: proc "contextless" (x: int) -> int {
|
||||
k := x -1
|
||||
when size_of(int) == 8 {
|
||||
k = k | (k >> 32)
|
||||
if x <= 1 {
|
||||
return 1
|
||||
}
|
||||
k = k | (k >> 16)
|
||||
k = k | (k >> 8)
|
||||
k = k | (k >> 4)
|
||||
k = k | (k >> 2)
|
||||
k = k | (k >> 1)
|
||||
k += 1 + int(x <= 0)
|
||||
return k
|
||||
n := uint(size_of(x) * 8) - uint(intrinsics.count_leading_zeros(uint(x) - 1))
|
||||
return int(1) << n
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
|
||||
@@ -255,11 +255,10 @@ alignment is not specified explicitly.
|
||||
DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
|
||||
|
||||
/*
|
||||
Default page size.
|
||||
|
||||
This value is the default page size for the current platform.
|
||||
On platforms where we were able to query a configurable size, we use that value instead.
|
||||
See `query_page_size_init()`
|
||||
*/
|
||||
DEFAULT_PAGE_SIZE ::
|
||||
PAGE_SIZE: int =
|
||||
64 * 1024 when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 else
|
||||
16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
|
||||
4 * 1024
|
||||
|
||||
@@ -1621,20 +1621,6 @@ small_stack_allocator_proc :: proc(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
/* Preserved for compatibility */
|
||||
Dynamic_Pool :: Dynamic_Arena
|
||||
DYNAMIC_POOL_BLOCK_SIZE_DEFAULT :: DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT
|
||||
DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT :: DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT
|
||||
dynamic_pool_allocator_proc :: dynamic_arena_allocator_proc
|
||||
dynamic_pool_free_all :: dynamic_arena_free_all
|
||||
dynamic_pool_reset :: dynamic_arena_reset
|
||||
dynamic_pool_alloc_bytes :: dynamic_arena_alloc_bytes
|
||||
dynamic_pool_alloc :: dynamic_arena_alloc
|
||||
dynamic_pool_init :: dynamic_arena_init
|
||||
dynamic_pool_allocator :: dynamic_arena_allocator
|
||||
dynamic_pool_destroy :: dynamic_arena_destroy
|
||||
|
||||
/*
|
||||
Default block size for dynamic arena.
|
||||
*/
|
||||
@@ -1651,7 +1637,7 @@ Dynamic arena allocator data.
|
||||
Dynamic_Arena :: struct {
|
||||
block_size: int,
|
||||
out_band_size: int,
|
||||
alignment: int,
|
||||
minimum_alignment: int,
|
||||
unused_blocks: [dynamic]rawptr,
|
||||
used_blocks: [dynamic]rawptr,
|
||||
out_band_allocations: [dynamic]rawptr,
|
||||
@@ -1668,23 +1654,23 @@ This procedure initializes a dynamic arena. The specified `block_allocator`
|
||||
will be used to allocate arena blocks, and `array_allocator` to allocate
|
||||
arrays of blocks and out-band blocks. The blocks have the default size of
|
||||
`block_size` and out-band threshold will be `out_band_size`. All allocations
|
||||
will be aligned to a boundary specified by `alignment`.
|
||||
will be aligned at a minimum to a boundary specified by `minimum_alignment`.
|
||||
*/
|
||||
dynamic_arena_init :: proc(
|
||||
pool: ^Dynamic_Arena,
|
||||
block_allocator := context.allocator,
|
||||
array_allocator := context.allocator,
|
||||
block_size := DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT,
|
||||
out_band_size := DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT,
|
||||
alignment := DEFAULT_ALIGNMENT,
|
||||
arena: ^Dynamic_Arena,
|
||||
block_allocator := context.allocator,
|
||||
array_allocator := context.allocator,
|
||||
block_size := DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT,
|
||||
out_band_size := DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT,
|
||||
minimum_alignment := DEFAULT_ALIGNMENT,
|
||||
) {
|
||||
pool.block_size = block_size
|
||||
pool.out_band_size = out_band_size
|
||||
pool.alignment = alignment
|
||||
pool.block_allocator = block_allocator
|
||||
pool.out_band_allocations.allocator = array_allocator
|
||||
pool.unused_blocks.allocator = array_allocator
|
||||
pool.used_blocks.allocator = array_allocator
|
||||
arena.block_size = block_size
|
||||
arena.out_band_size = out_band_size
|
||||
arena.minimum_alignment = minimum_alignment
|
||||
arena.block_allocator = block_allocator
|
||||
arena.out_band_allocations.allocator = array_allocator
|
||||
arena.unused_blocks.allocator = array_allocator
|
||||
arena.used_blocks.allocator = array_allocator
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1728,7 +1714,7 @@ dynamic_arena_destroy :: proc(a: ^Dynamic_Arena) {
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
_dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, loc := #caller_location) -> (err: Allocator_Error) {
|
||||
_dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, alignment: int, loc := #caller_location) -> (err: Allocator_Error) {
|
||||
if a.block_allocator.procedure == nil {
|
||||
panic("You must call `dynamic_arena_init` on a Dynamic Arena before using it.", loc)
|
||||
}
|
||||
@@ -1744,7 +1730,7 @@ _dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, loc := #caller_locatio
|
||||
a.block_allocator.data,
|
||||
Allocator_Mode.Alloc,
|
||||
a.block_size,
|
||||
a.alignment,
|
||||
max(a.minimum_alignment, alignment),
|
||||
nil,
|
||||
0,
|
||||
)
|
||||
@@ -1766,8 +1752,8 @@ zero-initialized. This procedure returns a pointer to the newly allocated memory
|
||||
region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_alloc :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> (rawptr, Allocator_Error) {
|
||||
data, err := dynamic_arena_alloc_bytes(a, size, loc)
|
||||
dynamic_arena_alloc :: proc(a: ^Dynamic_Arena, size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> (rawptr, Allocator_Error) {
|
||||
data, err := dynamic_arena_alloc_bytes(a, size, alignment, loc)
|
||||
return raw_data(data), err
|
||||
}
|
||||
|
||||
@@ -1780,8 +1766,8 @@ zero-initialized. This procedure returns a slice of the newly allocated memory
|
||||
region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_alloc_bytes :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
bytes, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc)
|
||||
dynamic_arena_alloc_bytes :: proc(a: ^Dynamic_Arena, size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
bytes, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, alignment, loc)
|
||||
if bytes != nil {
|
||||
zero_slice(bytes)
|
||||
}
|
||||
@@ -1797,8 +1783,8 @@ zero-initialized. This procedure returns a pointer to the newly allocated
|
||||
memory region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_alloc_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> (rawptr, Allocator_Error) {
|
||||
data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc)
|
||||
dynamic_arena_alloc_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> (rawptr, Allocator_Error) {
|
||||
data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, alignment, loc)
|
||||
return raw_data(data), err
|
||||
}
|
||||
|
||||
@@ -1811,21 +1797,21 @@ zero-initialized. This procedure returns a slice of the newly allocated
|
||||
memory region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
if size >= a.out_band_size {
|
||||
assert(a.out_band_allocations.allocator.procedure != nil, "Backing array allocator must be initialized", loc=loc)
|
||||
memory, err := alloc_bytes_non_zeroed(size, a.alignment, a.out_band_allocations.allocator, loc)
|
||||
memory, err := alloc_bytes_non_zeroed(size, alignment, a.out_band_allocations.allocator, loc)
|
||||
if memory != nil {
|
||||
append(&a.out_band_allocations, raw_data(memory), loc = loc)
|
||||
}
|
||||
return memory, err
|
||||
}
|
||||
n := align_formula(size, a.alignment)
|
||||
n := align_formula(size, max(a.minimum_alignment, alignment))
|
||||
if n > a.block_size {
|
||||
return nil, .Invalid_Argument
|
||||
}
|
||||
if a.bytes_left < n {
|
||||
err := _dynamic_arena_cycle_new_block(a, loc)
|
||||
err := _dynamic_arena_cycle_new_block(a, alignment, loc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1900,9 +1886,10 @@ dynamic_arena_resize :: proc(
|
||||
old_memory: rawptr,
|
||||
old_size: int,
|
||||
size: int,
|
||||
alignment: int = DEFAULT_ALIGNMENT,
|
||||
loc := #caller_location,
|
||||
) -> (rawptr, Allocator_Error) {
|
||||
bytes, err := dynamic_arena_resize_bytes(a, byte_slice(old_memory, old_size), size, loc)
|
||||
bytes, err := dynamic_arena_resize_bytes(a, byte_slice(old_memory, old_size), size, alignment, loc)
|
||||
return raw_data(bytes), err
|
||||
}
|
||||
|
||||
@@ -1921,16 +1908,17 @@ This procedure returns the slice of the resized memory region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_resize_bytes :: proc(
|
||||
a: ^Dynamic_Arena,
|
||||
old_data: []byte,
|
||||
size: int,
|
||||
a: ^Dynamic_Arena,
|
||||
old_data: []byte,
|
||||
size: int,
|
||||
alignment: int = DEFAULT_ALIGNMENT,
|
||||
loc := #caller_location,
|
||||
) -> ([]byte, Allocator_Error) {
|
||||
if size == 0 {
|
||||
// NOTE: This allocator has no Free mode.
|
||||
return nil, nil
|
||||
}
|
||||
bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, old_data, size, loc)
|
||||
bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, old_data, size, alignment, loc)
|
||||
if bytes != nil {
|
||||
if old_data == nil {
|
||||
zero_slice(bytes)
|
||||
@@ -1960,9 +1948,10 @@ dynamic_arena_resize_non_zeroed :: proc(
|
||||
old_memory: rawptr,
|
||||
old_size: int,
|
||||
size: int,
|
||||
alignment: int = DEFAULT_ALIGNMENT,
|
||||
loc := #caller_location,
|
||||
) -> (rawptr, Allocator_Error) {
|
||||
bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, byte_slice(old_memory, old_size), size, loc)
|
||||
bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, byte_slice(old_memory, old_size), size, alignment, loc)
|
||||
return raw_data(bytes), err
|
||||
}
|
||||
|
||||
@@ -1981,9 +1970,10 @@ This procedure returns the slice of the resized memory region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_resize_bytes_non_zeroed :: proc(
|
||||
a: ^Dynamic_Arena,
|
||||
old_data: []byte,
|
||||
size: int,
|
||||
a: ^Dynamic_Arena,
|
||||
old_data: []byte,
|
||||
size: int,
|
||||
alignment: int = DEFAULT_ALIGNMENT,
|
||||
loc := #caller_location,
|
||||
) -> ([]byte, Allocator_Error) {
|
||||
if size == 0 {
|
||||
@@ -1998,7 +1988,7 @@ dynamic_arena_resize_bytes_non_zeroed :: proc(
|
||||
}
|
||||
// No information is kept about allocations in this allocator, thus we
|
||||
// cannot truly resize anything and must reallocate.
|
||||
data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc)
|
||||
data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, alignment, loc)
|
||||
if err == nil {
|
||||
runtime.copy(data, byte_slice(old_memory, old_size))
|
||||
}
|
||||
@@ -2017,17 +2007,17 @@ dynamic_arena_allocator_proc :: proc(
|
||||
arena := (^Dynamic_Arena)(allocator_data)
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
return dynamic_arena_alloc_bytes(arena, size, loc)
|
||||
return dynamic_arena_alloc_bytes(arena, size, alignment, loc)
|
||||
case .Alloc_Non_Zeroed:
|
||||
return dynamic_arena_alloc_bytes_non_zeroed(arena, size, loc)
|
||||
return dynamic_arena_alloc_bytes_non_zeroed(arena, size, alignment, loc)
|
||||
case .Free:
|
||||
return nil, .Mode_Not_Implemented
|
||||
case .Free_All:
|
||||
dynamic_arena_free_all(arena, loc)
|
||||
case .Resize:
|
||||
return dynamic_arena_resize_bytes(arena, byte_slice(old_memory, old_size), size, loc)
|
||||
return dynamic_arena_resize_bytes(arena, byte_slice(old_memory, old_size), size, alignment, loc)
|
||||
case .Resize_Non_Zeroed:
|
||||
return dynamic_arena_resize_bytes_non_zeroed(arena, byte_slice(old_memory, old_size), size, loc)
|
||||
return dynamic_arena_resize_bytes_non_zeroed(arena, byte_slice(old_memory, old_size), size, alignment, loc)
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
@@ -2038,7 +2028,7 @@ dynamic_arena_allocator_proc :: proc(
|
||||
info := (^Allocator_Query_Info)(old_memory)
|
||||
if info != nil && info.pointer != nil {
|
||||
info.size = arena.block_size
|
||||
info.alignment = arena.alignment
|
||||
info.alignment = arena.minimum_alignment
|
||||
return byte_slice(info, size_of(info^)), nil
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
13
core/mem/mem_posix.odin
Normal file
13
core/mem/mem_posix.odin
Normal file
@@ -0,0 +1,13 @@
|
||||
#+build linux, darwin, netbsd, freebsd, openbsd
|
||||
package mem
|
||||
|
||||
import "core:sys/posix"
|
||||
|
||||
@(init, private, no_sanitize_address)
|
||||
query_page_size_init :: proc "contextless" () {
|
||||
size := posix.sysconf(._PAGESIZE)
|
||||
PAGE_SIZE = max(PAGE_SIZE, int(size))
|
||||
|
||||
// is power of two
|
||||
assert_contextless(PAGE_SIZE != 0 && (PAGE_SIZE & (PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
16
core/mem/mem_windows.odin
Normal file
16
core/mem/mem_windows.odin
Normal file
@@ -0,0 +1,16 @@
|
||||
#+build windows
|
||||
package mem
|
||||
|
||||
import "core:sys/windows"
|
||||
|
||||
@(init, private, no_sanitize_address)
|
||||
query_page_size_init :: proc "contextless" () {
|
||||
info: windows.SYSTEM_INFO
|
||||
windows.GetSystemInfo(&info)
|
||||
|
||||
size := info.dwPageSize
|
||||
PAGE_SIZE = max(PAGE_SIZE, int(size))
|
||||
|
||||
// is power of two
|
||||
assert_contextless(PAGE_SIZE != 0 && (PAGE_SIZE & (PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
@@ -126,11 +126,11 @@ arena_alloc_unguarded :: proc(arena: ^Arena, size: uint, alignment: uint, loc :=
|
||||
if err == .Out_Of_Memory {
|
||||
if arena.minimum_block_size == 0 {
|
||||
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||
arena.minimum_block_size = mem.align_forward_uint(arena.minimum_block_size, DEFAULT_PAGE_SIZE)
|
||||
arena.minimum_block_size = mem.align_forward_uint(arena.minimum_block_size, uint(mem.PAGE_SIZE))
|
||||
}
|
||||
if arena.default_commit_size == 0 {
|
||||
arena.default_commit_size = min(DEFAULT_ARENA_GROWING_COMMIT_SIZE, arena.minimum_block_size)
|
||||
arena.default_commit_size = mem.align_forward_uint(arena.default_commit_size, DEFAULT_PAGE_SIZE)
|
||||
arena.default_commit_size = mem.align_forward_uint(arena.default_commit_size, uint(mem.PAGE_SIZE))
|
||||
}
|
||||
|
||||
if arena.default_commit_size != 0 {
|
||||
|
||||
@@ -6,13 +6,6 @@ import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
_ :: runtime
|
||||
|
||||
DEFAULT_PAGE_SIZE := uint(4096)
|
||||
|
||||
@(init, private)
|
||||
platform_memory_init :: proc "contextless" () {
|
||||
_platform_memory_init()
|
||||
}
|
||||
|
||||
Allocator_Error :: mem.Allocator_Error
|
||||
|
||||
@(require_results, no_sanitize_address)
|
||||
@@ -79,7 +72,7 @@ align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint {
|
||||
|
||||
@(require_results, no_sanitize_address)
|
||||
memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags: Memory_Block_Flags = {}) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
page_size := DEFAULT_PAGE_SIZE
|
||||
page_size := uint(mem.PAGE_SIZE)
|
||||
assert(mem.is_power_of_two(uintptr(page_size)))
|
||||
|
||||
committed := committed
|
||||
@@ -144,7 +137,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint,
|
||||
// TODO(bill): determine a better heuristic for this behaviour
|
||||
extra_size := max(size, block.committed>>1)
|
||||
platform_total_commit := base_offset + block.used + extra_size
|
||||
platform_total_commit = align_formula(platform_total_commit, DEFAULT_PAGE_SIZE)
|
||||
platform_total_commit = align_formula(platform_total_commit, uint(mem.PAGE_SIZE))
|
||||
platform_total_commit = min(max(platform_total_commit, default_commit_size), pmblock.reserved)
|
||||
|
||||
assert(pmblock.committed <= pmblock.reserved)
|
||||
|
||||
@@ -43,12 +43,6 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return errno == .NONE
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
DEFAULT_PAGE_SIZE = 4096
|
||||
// is power of two
|
||||
assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
prot: linux.Mem_Protection
|
||||
if .Read in flags {
|
||||
|
||||
@@ -25,10 +25,6 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return false
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
|
||||
}
|
||||
|
||||
_map_file :: proc "contextless" (f: any, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
return nil, .Map_Failure
|
||||
}
|
||||
|
||||
@@ -28,15 +28,6 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
// NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
|
||||
size := posix.sysconf(._PAGESIZE)
|
||||
DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
|
||||
|
||||
// is power of two
|
||||
assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
#assert(i32(posix.Prot_Flag_Bits.READ) == i32(Map_File_Flag.Read))
|
||||
#assert(i32(posix.Prot_Flag_Bits.WRITE) == i32(Map_File_Flag.Write))
|
||||
|
||||
@@ -146,18 +146,6 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return bool(ok)
|
||||
}
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
sys_info: SYSTEM_INFO
|
||||
GetSystemInfo(&sys_info)
|
||||
DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize))
|
||||
|
||||
// is power of two
|
||||
assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
page_flags: u32
|
||||
|
||||
@@ -216,18 +216,18 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator, loc :
|
||||
return
|
||||
} else {
|
||||
buffer: [1024]u8
|
||||
out_buffer := make([dynamic]u8, 0, 0, allocator, loc)
|
||||
total := 0
|
||||
out_buffer := make([dynamic]u8, 0, 0, allocator, loc) or_return
|
||||
for {
|
||||
n: int
|
||||
n, err = read(f, buffer[:])
|
||||
total += n
|
||||
append_elems(&out_buffer, ..buffer[:n], loc=loc) or_return
|
||||
if _, aerr := append_elems(&out_buffer, ..buffer[:n], loc=loc); aerr != nil {
|
||||
return out_buffer[:], aerr
|
||||
}
|
||||
if err != nil {
|
||||
if err == .EOF || err == .Broken_Pipe {
|
||||
err = nil
|
||||
}
|
||||
data = out_buffer[:total]
|
||||
data = out_buffer[:]
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,17 +571,18 @@ foreign kernel32 {
|
||||
DisconnectNamedPipe :: proc(hNamedPipe: HANDLE) -> BOOL ---
|
||||
WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL ---
|
||||
|
||||
AllocConsole :: proc() -> BOOL ---
|
||||
AttachConsole :: proc(dwProcessId: DWORD) -> BOOL ---
|
||||
SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL ---
|
||||
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
|
||||
FreeConsole :: proc() -> BOOL ---
|
||||
GetConsoleWindow :: proc() -> HWND ---
|
||||
GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL ---
|
||||
SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL ---
|
||||
SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL ---
|
||||
GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
|
||||
SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
|
||||
AllocConsole :: proc() -> BOOL ---
|
||||
AttachConsole :: proc(dwProcessId: DWORD) -> BOOL ---
|
||||
SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL ---
|
||||
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
|
||||
FreeConsole :: proc() -> BOOL ---
|
||||
GetConsoleWindow :: proc() -> HWND ---
|
||||
GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL ---
|
||||
GetConsoleScreenBufferInfoEx :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfoEx: PCONSOLE_SCREEN_BUFFER_INFOEX) -> BOOL ---
|
||||
SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL ---
|
||||
SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL ---
|
||||
GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
|
||||
SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
|
||||
|
||||
GetDiskFreeSpaceExW :: proc(
|
||||
lpDirectoryName: LPCWSTR,
|
||||
|
||||
@@ -3411,9 +3411,21 @@ CONSOLE_READCONSOLE_CONTROL :: struct {
|
||||
dwCtrlWakeupMask: ULONG,
|
||||
dwControlKeyState: ULONG,
|
||||
}
|
||||
|
||||
PCONSOLE_READCONSOLE_CONTROL :: ^CONSOLE_READCONSOLE_CONTROL
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX :: struct {
|
||||
cbSize: ULONG,
|
||||
dwSize: COORD,
|
||||
dwCursorPosition: COORD,
|
||||
wAttributes: WORD,
|
||||
srWindow: SMALL_RECT,
|
||||
dwMaximumWindowSize: COORD,
|
||||
wPopupAttributes: WORD,
|
||||
bFullscreenSupported: BOOL,
|
||||
ColorTable: [16]COLORREF,
|
||||
}
|
||||
PCONSOLE_SCREEN_BUFFER_INFOEX :: ^CONSOLE_SCREEN_BUFFER_INFOEX
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION :: struct {
|
||||
dwFileAttributes: DWORD,
|
||||
ftCreationTime: FILETIME,
|
||||
@@ -3426,7 +3438,6 @@ BY_HANDLE_FILE_INFORMATION :: struct {
|
||||
nFileIndexHigh: DWORD,
|
||||
nFileIndexLow: DWORD,
|
||||
}
|
||||
|
||||
LPBY_HANDLE_FILE_INFORMATION :: ^BY_HANDLE_FILE_INFORMATION
|
||||
|
||||
FILE_STANDARD_INFO :: struct {
|
||||
|
||||
@@ -51,8 +51,6 @@ Example:
|
||||
Tn :: i18n.get_n
|
||||
|
||||
mo :: proc() {
|
||||
using fmt
|
||||
|
||||
err: i18n.Error
|
||||
|
||||
// Parse MO file and set it as the active translation so we can omit `get`'s "catalog" parameter.
|
||||
@@ -62,26 +60,24 @@ Example:
|
||||
if err != .None { return }
|
||||
|
||||
// These are in the .MO catalog.
|
||||
println("-----")
|
||||
println(T(""))
|
||||
println("-----")
|
||||
println(T("There are 69,105 leaves here."))
|
||||
println("-----")
|
||||
println(T("Hellope, World!"))
|
||||
println("-----")
|
||||
fmt.println("-----")
|
||||
fmt.println(T(""))
|
||||
fmt.println("-----")
|
||||
fmt.println(T("There are 69,105 leaves here."))
|
||||
fmt.println("-----")
|
||||
fmt.println(T("Hellope, World!"))
|
||||
fmt.println("-----")
|
||||
// We pass 1 into `T` to get the singular format string, then 1 again into printf.
|
||||
printf(Tn("There is %d leaf.\n", 1), 1)
|
||||
fmt.printf(Tn("There is %d leaf.\n", 1), 1)
|
||||
// We pass 42 into `T` to get the plural format string, then 42 again into printf.
|
||||
printf(Tn("There is %d leaf.\n", 42), 42)
|
||||
fmt.printf(Tn("There is %d leaf.\n", 42), 42)
|
||||
|
||||
// This isn't in the translation catalog, so the key is passed back untranslated.
|
||||
println("-----")
|
||||
println(T("Come visit us on Discord!"))
|
||||
fmt.println("-----")
|
||||
fmt.println(T("Come visit us on Discord!"))
|
||||
}
|
||||
|
||||
qt :: proc() {
|
||||
using fmt
|
||||
|
||||
err: i18n.Error
|
||||
|
||||
// Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter.
|
||||
@@ -91,18 +87,18 @@ Example:
|
||||
if err != .None { return }
|
||||
|
||||
// These are in the .TS catalog. As you can see they have sections.
|
||||
println("--- Page section ---")
|
||||
println("Page:Text for translation =", T("Page", "Text for translation"))
|
||||
println("-----")
|
||||
println("Page:Also text to translate =", T("Page", "Also text to translate"))
|
||||
println("-----")
|
||||
println("--- installscript section ---")
|
||||
println("installscript:99 bottles of beer on the wall =", T("installscript", "99 bottles of beer on the wall"))
|
||||
println("-----")
|
||||
println("--- apple_count section ---")
|
||||
println("apple_count:%d apple(s) =")
|
||||
println("\t 1 =", Tn("apple_count", "%d apple(s)", 1))
|
||||
println("\t 42 =", Tn("apple_count", "%d apple(s)", 42))
|
||||
fmt.println("--- Page section ---")
|
||||
fmt.println("Page:Text for translation =", T("Page", "Text for translation"))
|
||||
fmt.println("-----")
|
||||
fmt.println("Page:Also text to translate =", T("Page", "Also text to translate"))
|
||||
fmt.println("-----")
|
||||
fmt.println("--- installscript section ---")
|
||||
fmt.println("installscript:99 bottles of beer on the wall =", T("installscript", "99 bottles of beer on the wall"))
|
||||
fmt.println("-----")
|
||||
fmt.println("--- apple_count section ---")
|
||||
fmt.println("apple_count:%d apple(s) =")
|
||||
fmt.println("\t 1 =", Tn("apple_count", "%d apple(s)", 1))
|
||||
fmt.println("\t 42 =", Tn("apple_count", "%d apple(s)", 42))
|
||||
}
|
||||
*/
|
||||
package i18n
|
||||
|
||||
@@ -6595,11 +6595,16 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
positional_operand_count = gb_min(positional_operands.count, pt->variadic_index);
|
||||
} else if (positional_operand_count > pt->param_count) {
|
||||
err = CallArgumentError_TooManyArguments;
|
||||
char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td";
|
||||
if (show_error) {
|
||||
gbString proc_str = expr_to_string(ce->proc);
|
||||
defer (gb_string_free(proc_str));
|
||||
error(call, err_fmt, proc_str, param_count_excluding_defaults, positional_operands.count);
|
||||
if (param_count_excluding_defaults != pt->param_count) {
|
||||
char const *err_fmt = "Too many arguments for '%s', expected %td..=%td arguments, got %td";
|
||||
error(call, err_fmt, proc_str, param_count_excluding_defaults, pt->param_count, positional_operands.count);
|
||||
} else {
|
||||
char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td";
|
||||
error(call, err_fmt, proc_str, pt->param_count, positional_operands.count);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2493,7 +2493,13 @@ extern "C" {
|
||||
#pragma warning(disable:4127) // Conditional expression is constant
|
||||
#endif
|
||||
|
||||
gb_internal void print_all_errors(void);
|
||||
gb_internal bool any_errors(void);
|
||||
gb_internal bool any_warnings(void);
|
||||
void gb_assert_handler(char const *prefix, char const *condition, char const *file, i32 line, char const *msg, ...) {
|
||||
if (any_errors() || any_warnings()) {
|
||||
print_all_errors();
|
||||
}
|
||||
gb_printf_err("%s(%d): %s: ", file, line, prefix);
|
||||
if (condition)
|
||||
gb_printf_err( "`%s` ", condition);
|
||||
|
||||
@@ -307,7 +307,7 @@ test_all_bit_sets :: proc(t: ^testing.T) {
|
||||
"-a:10101",
|
||||
"-b:0000_0000_0000_0001",
|
||||
"-c:11",
|
||||
"-d:___1",
|
||||
"-d:1",
|
||||
"-e:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||
"-f:1",
|
||||
"-g:01",
|
||||
@@ -333,6 +333,65 @@ test_all_bit_sets :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value)
|
||||
}
|
||||
}
|
||||
{
|
||||
// Starting a binary string with underscore is disallowed.
|
||||
args := [?]string { "-d:_1" }
|
||||
result := flags.parse(&s, args[:])
|
||||
err, ok := result.(flags.Parse_Error)
|
||||
testing.expectf(t, ok, "unexpected result: %v", result)
|
||||
if ok {
|
||||
testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value)
|
||||
}
|
||||
}
|
||||
|
||||
E2 :: enum {
|
||||
Option_A=5,
|
||||
Option_B,
|
||||
Option_C=3,
|
||||
Option_D,
|
||||
}
|
||||
R :: struct {
|
||||
a: bit_set[E2],
|
||||
}
|
||||
r: R
|
||||
{
|
||||
// Least significant bit > 0
|
||||
args := [?]string {
|
||||
"-a:Option_A,Option_D",
|
||||
}
|
||||
result := flags.parse(&r, args[:])
|
||||
testing.expect_value(t, result, nil)
|
||||
testing.expect_value(t, r.a, bit_set[E2]{E2.Option_A, E2.Option_D})
|
||||
}
|
||||
{
|
||||
args := [?]string { "-a:Option_Non_Existent" }
|
||||
result := flags.parse(&r, args[:])
|
||||
err, ok := result.(flags.Parse_Error)
|
||||
testing.expectf(t, ok, "unexpected result: %v", result)
|
||||
if ok {
|
||||
testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value)
|
||||
}
|
||||
}
|
||||
{
|
||||
// Value names list must be strictly comma-separated.
|
||||
args := [?]string { "-a:Option_A, Option_B" }
|
||||
result := flags.parse(&r, args[:])
|
||||
err, ok := result.(flags.Parse_Error)
|
||||
testing.expectf(t, ok, "unexpected result: %v", result)
|
||||
if ok {
|
||||
testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value)
|
||||
}
|
||||
}
|
||||
{
|
||||
// Value names list must not end with a comma.
|
||||
args := [?]string { "-a:Option_A,Option_B," }
|
||||
result := flags.parse(&r, args[:])
|
||||
err, ok := result.(flags.Parse_Error)
|
||||
testing.expectf(t, ok, "unexpected result: %v", result)
|
||||
if ok {
|
||||
testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
@@ -1288,13 +1347,11 @@ test_distinct_types :: proc(t: ^testing.T) {
|
||||
unmodified_i: I,
|
||||
}
|
||||
s: S
|
||||
|
||||
{
|
||||
args := [?]string {"-base-i:1"}
|
||||
result := flags.parse(&s, args[:])
|
||||
testing.expect_value(t, result, nil)
|
||||
}
|
||||
|
||||
{
|
||||
args := [?]string {"-unmodified-i:1"}
|
||||
result := flags.parse(&s, args[:])
|
||||
|
||||
103
tests/core/mem/test_mem_dynamic_arena.odin
Normal file
103
tests/core/mem/test_mem_dynamic_arena.odin
Normal file
@@ -0,0 +1,103 @@
|
||||
package test_core_mem
|
||||
|
||||
import "core:testing"
|
||||
import "core:mem"
|
||||
|
||||
|
||||
expect_arena_allocation :: proc(t: ^testing.T, expected_used_bytes, num_bytes, alignment: int) {
|
||||
arena: mem.Dynamic_Arena
|
||||
mem.dynamic_arena_init(&arena, minimum_alignment = alignment)
|
||||
arena_allocator := mem.dynamic_arena_allocator(&arena)
|
||||
|
||||
element, err := mem.alloc(num_bytes, alignment, arena_allocator)
|
||||
testing.expect(t, err == .None)
|
||||
testing.expect(t, element != nil)
|
||||
|
||||
expected_bytes_left := arena.block_size - expected_used_bytes
|
||||
testing.expectf(t, arena.bytes_left == expected_bytes_left,
|
||||
`
|
||||
Allocated data with size %v bytes, expected %v bytes left, got %v bytes left, off by %v bytes.
|
||||
Pool:
|
||||
block_size = %v
|
||||
out_band_size = %v
|
||||
minimum_alignment = %v
|
||||
unused_blocks = %v
|
||||
used_blocks = %v
|
||||
out_band_allocations = %v
|
||||
current_block = %v
|
||||
current_pos = %v
|
||||
bytes_left = %v
|
||||
`,
|
||||
num_bytes, expected_bytes_left, arena.bytes_left, expected_bytes_left - arena.bytes_left,
|
||||
arena.block_size,
|
||||
arena.out_band_size,
|
||||
arena.minimum_alignment,
|
||||
arena.unused_blocks,
|
||||
arena.used_blocks,
|
||||
arena.out_band_allocations,
|
||||
arena.current_block,
|
||||
arena.current_pos,
|
||||
arena.bytes_left,
|
||||
)
|
||||
testing.expectf(t, uintptr(element) % uintptr(alignment) == 0, "Expected allocation to be aligned to %d byte boundary, got %v", alignment, element)
|
||||
|
||||
mem.dynamic_arena_destroy(&arena)
|
||||
testing.expect(t, arena.used_blocks == nil)
|
||||
}
|
||||
|
||||
expect_arena_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, block_size, out_band_size: int) {
|
||||
testing.expect(t, num_bytes >= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!")
|
||||
|
||||
arena: mem.Dynamic_Arena
|
||||
mem.dynamic_arena_init(&arena, block_size = block_size, out_band_size = out_band_size)
|
||||
arena_allocator := mem.dynamic_arena_allocator(&arena)
|
||||
|
||||
element, err := mem.alloc(num_bytes, allocator = arena_allocator)
|
||||
testing.expect(t, err == .None)
|
||||
testing.expect(t, element != nil)
|
||||
testing.expectf(t, arena.out_band_allocations != nil,
|
||||
"Allocated data with size %v bytes, which is >= out_of_band_size and it should be in arena.out_band_allocations, but isn't!",
|
||||
)
|
||||
|
||||
mem.dynamic_arena_destroy(&arena)
|
||||
testing.expect(t, arena.out_band_allocations == nil)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_arena_alloc_aligned :: proc(t: ^testing.T) {
|
||||
expect_arena_allocation(t, expected_used_bytes = 16, num_bytes = 16, alignment=8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_arena_alloc_unaligned :: proc(t: ^testing.T) {
|
||||
expect_arena_allocation(t, expected_used_bytes = 8, num_bytes = 1, alignment = 8)
|
||||
expect_arena_allocation(t, expected_used_bytes = 16, num_bytes = 9, alignment = 8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_arena_alloc_out_of_band :: proc(t: ^testing.T) {
|
||||
expect_arena_allocation_out_of_band(t, num_bytes = 128, block_size = 512, out_band_size = 128)
|
||||
expect_arena_allocation_out_of_band(t, num_bytes = 129, block_size = 512, out_band_size = 128)
|
||||
expect_arena_allocation_out_of_band(t, num_bytes = 513, block_size = 512, out_band_size = 128)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_intentional_leaks :: proc(t: ^testing.T) {
|
||||
testing.expect_leaks(t, intentionally_leaky_test, leak_verifier)
|
||||
}
|
||||
|
||||
// Not tagged with @(test) because it's run through `test_intentional_leaks`
|
||||
intentionally_leaky_test :: proc(t: ^testing.T) {
|
||||
a: [dynamic]int
|
||||
// Intentional leak
|
||||
append(&a, 42)
|
||||
|
||||
// Intentional bad free
|
||||
b := uintptr(&a[0]) + 42
|
||||
free(rawptr(b))
|
||||
}
|
||||
|
||||
leak_verifier :: proc(t: ^testing.T, ta: ^mem.Tracking_Allocator) {
|
||||
testing.expect_value(t, len(ta.allocation_map), 1)
|
||||
testing.expect_value(t, len(ta.bad_free_array), 1)
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package test_core_mem
|
||||
|
||||
import "core:testing"
|
||||
import "core:mem"
|
||||
|
||||
|
||||
expect_pool_allocation :: proc(t: ^testing.T, expected_used_bytes, num_bytes, alignment: int) {
|
||||
pool: mem.Dynamic_Pool
|
||||
mem.dynamic_pool_init(&pool, alignment = alignment)
|
||||
pool_allocator := mem.dynamic_pool_allocator(&pool)
|
||||
|
||||
element, err := mem.alloc(num_bytes, alignment, pool_allocator)
|
||||
testing.expect(t, err == .None)
|
||||
testing.expect(t, element != nil)
|
||||
|
||||
expected_bytes_left := pool.block_size - expected_used_bytes
|
||||
testing.expectf(t, pool.bytes_left == expected_bytes_left,
|
||||
`
|
||||
Allocated data with size %v bytes, expected %v bytes left, got %v bytes left, off by %v bytes.
|
||||
Pool:
|
||||
block_size = %v
|
||||
out_band_size = %v
|
||||
alignment = %v
|
||||
unused_blocks = %v
|
||||
used_blocks = %v
|
||||
out_band_allocations = %v
|
||||
current_block = %v
|
||||
current_pos = %v
|
||||
bytes_left = %v
|
||||
`,
|
||||
num_bytes, expected_bytes_left, pool.bytes_left, expected_bytes_left - pool.bytes_left,
|
||||
pool.block_size,
|
||||
pool.out_band_size,
|
||||
pool.alignment,
|
||||
pool.unused_blocks,
|
||||
pool.used_blocks,
|
||||
pool.out_band_allocations,
|
||||
pool.current_block,
|
||||
pool.current_pos,
|
||||
pool.bytes_left,
|
||||
)
|
||||
|
||||
mem.dynamic_pool_destroy(&pool)
|
||||
testing.expect(t, pool.used_blocks == nil)
|
||||
}
|
||||
|
||||
expect_pool_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, block_size, out_band_size: int) {
|
||||
testing.expect(t, num_bytes >= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!")
|
||||
|
||||
pool: mem.Dynamic_Pool
|
||||
mem.dynamic_pool_init(&pool, block_size = block_size, out_band_size = out_band_size)
|
||||
pool_allocator := mem.dynamic_pool_allocator(&pool)
|
||||
|
||||
element, err := mem.alloc(num_bytes, allocator = pool_allocator)
|
||||
testing.expect(t, err == .None)
|
||||
testing.expect(t, element != nil)
|
||||
testing.expectf(t, pool.out_band_allocations != nil,
|
||||
"Allocated data with size %v bytes, which is >= out_of_band_size and it should be in pool.out_band_allocations, but isn't!",
|
||||
)
|
||||
|
||||
mem.dynamic_pool_destroy(&pool)
|
||||
testing.expect(t, pool.out_band_allocations == nil)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_pool_alloc_aligned :: proc(t: ^testing.T) {
|
||||
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 16, alignment=8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_pool_alloc_unaligned :: proc(t: ^testing.T) {
|
||||
expect_pool_allocation(t, expected_used_bytes = 8, num_bytes = 1, alignment = 8)
|
||||
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 9, alignment = 8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_pool_alloc_out_of_band :: proc(t: ^testing.T) {
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 128, block_size = 512, out_band_size = 128)
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 129, block_size = 512, out_band_size = 128)
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 513, block_size = 512, out_band_size = 128)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_intentional_leaks :: proc(t: ^testing.T) {
|
||||
testing.expect_leaks(t, intentionally_leaky_test, leak_verifier)
|
||||
}
|
||||
|
||||
// Not tagged with @(test) because it's run through `test_intentional_leaks`
|
||||
intentionally_leaky_test :: proc(t: ^testing.T) {
|
||||
a: [dynamic]int
|
||||
// Intentional leak
|
||||
append(&a, 42)
|
||||
|
||||
// Intentional bad free
|
||||
b := uintptr(&a[0]) + 42
|
||||
free(rawptr(b))
|
||||
}
|
||||
|
||||
leak_verifier :: proc(t: ^testing.T, ta: ^mem.Tracking_Allocator) {
|
||||
testing.expect_value(t, len(ta.allocation_map), 1)
|
||||
testing.expect_value(t, len(ta.bad_free_array), 1)
|
||||
}
|
||||
20
vendor/raylib/rlgl/rlgl.odin
vendored
20
vendor/raylib/rlgl/rlgl.odin
vendored
@@ -431,17 +431,19 @@ foreign lib {
|
||||
EnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap
|
||||
DisableTextureCubemap :: proc() --- // Disable texture cubemap
|
||||
TextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
|
||||
CubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap)
|
||||
CubemapParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap)
|
||||
|
||||
// Shader state
|
||||
EnableShader :: proc(id: c.uint) --- // Enable shader program
|
||||
DisableShader :: proc() --- // Disable shader program
|
||||
|
||||
// Framebuffer state
|
||||
EnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo)
|
||||
DisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer
|
||||
ActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers
|
||||
BlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
|
||||
EnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo)
|
||||
DisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer
|
||||
GetActiveFramebuffer :: proc() -> c.uint --- // Get the currently active render texture (fbo), 0 for default framebuffer
|
||||
ActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers
|
||||
BlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight: c.int, dstX, dstY, dstWidth, dstHeight: c.int, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
|
||||
BindFramebuffer :: proc(target, framebuffer: c.uint) --- // Bind framebuffer (FBO)
|
||||
|
||||
// General render state
|
||||
EnableColorBlend :: proc() --- // Enable color blending
|
||||
@@ -452,12 +454,13 @@ foreign lib {
|
||||
DisableDepthMask :: proc() --- // Disable depth write
|
||||
EnableBackfaceCulling :: proc() --- // Enable backface culling
|
||||
DisableBackfaceCulling :: proc() --- // Disable backface culling
|
||||
ColorMask :: proc(r, g, b, a: bool) --- // Color mask control
|
||||
SetCullFace :: proc(mode: CullMode) --- // Set face culling mode
|
||||
EnableScissorTest :: proc() --- // Enable scissor test
|
||||
DisableScissorTest :: proc() --- // Disable scissor test
|
||||
Scissor :: proc(x, y, width, height: c.int) --- // Scissor test
|
||||
EnableWireMode :: proc() --- // Enable wire mode
|
||||
EnablePointMode :: proc() --- // Enable point mode
|
||||
EnablePointMode :: proc() --- // Enable point mode
|
||||
DisableWireMode :: proc() --- // Disable wire and point modes
|
||||
SetLineWidth :: proc(width: f32) --- // Set the line drawing width
|
||||
GetLineWidth :: proc() -> f32 --- // Get the line drawing width
|
||||
@@ -503,7 +506,7 @@ foreign lib {
|
||||
DrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset)
|
||||
SetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal)
|
||||
DrawRenderBatchActive :: proc() --- // Update and draw internal render batch
|
||||
CheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex
|
||||
CheckRenderBatchLimit :: proc(vCount: c.int) -> bool --- // Check internal buffer overflow for a given number of vertex
|
||||
|
||||
SetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
|
||||
|
||||
@@ -528,7 +531,7 @@ foreign lib {
|
||||
// Textures management
|
||||
LoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU
|
||||
LoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo)
|
||||
LoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap
|
||||
LoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture cubemap
|
||||
UpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
|
||||
GetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats
|
||||
GetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format
|
||||
@@ -552,6 +555,7 @@ foreign lib {
|
||||
GetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute
|
||||
SetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
|
||||
SetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix
|
||||
SetUniformMatrices :: proc(locIndex: c.int, matrices: [^]Matrix, count: c.int) --- // Set shader value matrices
|
||||
SetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler
|
||||
SetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations)
|
||||
|
||||
|
||||
18
vendor/sdl3/sdl3_audio.odin
vendored
18
vendor/sdl3/sdl3_audio.odin
vendored
@@ -38,14 +38,14 @@ AudioFormat :: enum c.int {
|
||||
F32 = F32LE when BYTEORDER == LIL_ENDIAN else F32BE,
|
||||
}
|
||||
|
||||
@(require_results) AUDIO_BITSIZE :: proc "c" (x: AudioFormat) -> Uint16 { return (Uint16(x) & AUDIO_MASK_BITSIZE) }
|
||||
@(require_results) AUDIO_BYTESIZE :: proc "c" (x: AudioFormat) -> Uint16 { return AUDIO_BITSIZE(x) / 8 }
|
||||
@(require_results) AUDIO_ISFLOAT :: proc "c" (x: AudioFormat) -> bool { return (Uint16(x) & AUDIO_MASK_FLOAT) != 0 }
|
||||
@(require_results) AUDIO_ISBIGENDIAN :: proc "c" (x: AudioFormat) -> bool { return (Uint16(x) & AUDIO_MASK_BIG_ENDIAN) != 0 }
|
||||
@(require_results) AUDIO_ISLITTLEENDIAN :: proc "c" (x: AudioFormat) -> bool { return !AUDIO_ISBIGENDIAN(x) }
|
||||
@(require_results) AUDIO_ISSIGNED :: proc "c" (x: AudioFormat) -> bool { return (Uint16(x) & AUDIO_MASK_SIGNED) != 0 }
|
||||
@(require_results) AUDIO_ISINT :: proc "c" (x: AudioFormat) -> bool { return !AUDIO_ISFLOAT(x) }
|
||||
@(require_results) AUDIO_ISUNSIGNED :: proc "c" (x: AudioFormat) -> bool { return !AUDIO_ISSIGNED(x) }
|
||||
@(require_results) AUDIO_BITSIZE :: #force_inline proc "c" (x: AudioFormat) -> Uint16 { return (Uint16(x) & AUDIO_MASK_BITSIZE) }
|
||||
@(require_results) AUDIO_BYTESIZE :: #force_inline proc "c" (x: AudioFormat) -> Uint16 { return AUDIO_BITSIZE(x) / 8 }
|
||||
@(require_results) AUDIO_ISFLOAT :: #force_inline proc "c" (x: AudioFormat) -> bool { return (Uint16(x) & AUDIO_MASK_FLOAT) != 0 }
|
||||
@(require_results) AUDIO_ISBIGENDIAN :: #force_inline proc "c" (x: AudioFormat) -> bool { return (Uint16(x) & AUDIO_MASK_BIG_ENDIAN) != 0 }
|
||||
@(require_results) AUDIO_ISLITTLEENDIAN :: #force_inline proc "c" (x: AudioFormat) -> bool { return !AUDIO_ISBIGENDIAN(x) }
|
||||
@(require_results) AUDIO_ISSIGNED :: #force_inline proc "c" (x: AudioFormat) -> bool { return (Uint16(x) & AUDIO_MASK_SIGNED) != 0 }
|
||||
@(require_results) AUDIO_ISINT :: #force_inline proc "c" (x: AudioFormat) -> bool { return !AUDIO_ISFLOAT(x) }
|
||||
@(require_results) AUDIO_ISUNSIGNED :: #force_inline proc "c" (x: AudioFormat) -> bool { return !AUDIO_ISSIGNED(x) }
|
||||
|
||||
|
||||
AudioDeviceID :: distinct Uint32
|
||||
@@ -60,7 +60,7 @@ AudioSpec :: struct {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
AUDIO_FRAMESIZE :: proc "c" (x: AudioSpec) -> c.int {
|
||||
AUDIO_FRAMESIZE :: #force_inline proc "c" (x: AudioSpec) -> c.int {
|
||||
return c.int(AUDIO_BYTESIZE(x.format)) * x.channels
|
||||
}
|
||||
|
||||
|
||||
4
vendor/sdl3/sdl3_hints.odin
vendored
4
vendor/sdl3/sdl3_hints.odin
vendored
@@ -20,6 +20,7 @@ HINT_AUDIO_DEVICE_APP_ICON_NAME :: "SDL_AUDIO_DEVICE_APP_ICON_NAME"
|
||||
HINT_AUDIO_DEVICE_SAMPLE_FRAMES :: "SDL_AUDIO_DEVICE_SAMPLE_FRAMES"
|
||||
HINT_AUDIO_DEVICE_STREAM_NAME :: "SDL_AUDIO_DEVICE_STREAM_NAME"
|
||||
HINT_AUDIO_DEVICE_STREAM_ROLE :: "SDL_AUDIO_DEVICE_STREAM_ROLE"
|
||||
HINT_AUDIO_DEVICE_RAW_STREAM :: "SDL_AUDIO_DEVICE_RAW_STREAM"
|
||||
HINT_AUDIO_DISK_INPUT_FILE :: "SDL_AUDIO_DISK_INPUT_FILE"
|
||||
HINT_AUDIO_DISK_OUTPUT_FILE :: "SDL_AUDIO_DISK_OUTPUT_FILE"
|
||||
HINT_AUDIO_DISK_TIMESCALE :: "SDL_AUDIO_DISK_TIMESCALE"
|
||||
@@ -36,6 +37,7 @@ HINT_CPU_FEATURE_MASK :: "SDL_CPU_FEATURE_MASK"
|
||||
HINT_JOYSTICK_DIRECTINPUT :: "SDL_JOYSTICK_DIRECTINPUT"
|
||||
HINT_FILE_DIALOG_DRIVER :: "SDL_FILE_DIALOG_DRIVER"
|
||||
HINT_DISPLAY_USABLE_BOUNDS :: "SDL_DISPLAY_USABLE_BOUNDS"
|
||||
HINT_INVALID_PARAM_CHECKS :: "SDL_INVALID_PARAM_CHECKS"
|
||||
HINT_EMSCRIPTEN_ASYNCIFY :: "SDL_EMSCRIPTEN_ASYNCIFY"
|
||||
HINT_EMSCRIPTEN_CANVAS_SELECTOR :: "SDL_EMSCRIPTEN_CANVAS_SELECTOR"
|
||||
HINT_EMSCRIPTEN_KEYBOARD_ELEMENT :: "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT"
|
||||
@@ -56,6 +58,7 @@ HINT_GDK_TEXTINPUT_MAX_LENGTH :: "SDL_GDK_TEXTINPUT_MAX_LENGTH"
|
||||
HINT_GDK_TEXTINPUT_SCOPE :: "SDL_GDK_TEXTINPUT_SCOPE"
|
||||
HINT_GDK_TEXTINPUT_TITLE :: "SDL_GDK_TEXTINPUT_TITLE"
|
||||
HINT_HIDAPI_LIBUSB :: "SDL_HIDAPI_LIBUSB"
|
||||
HINT_HIDAPI_LIBUSB_GAMECUBE :: "SDL_HIDAPI_LIBUSB_GAMECUBE"
|
||||
HINT_HIDAPI_LIBUSB_WHITELIST :: "SDL_HIDAPI_LIBUSB_WHITELIST"
|
||||
HINT_HIDAPI_UDEV :: "SDL_HIDAPI_UDEV"
|
||||
HINT_GPU_DRIVER :: "SDL_GPU_DRIVER"
|
||||
@@ -247,6 +250,7 @@ HINT_WINDOWS_ENABLE_MENU_MNEMONICS :: "SDL_WINDOWS_ENABLE_MENU_MNEMONI
|
||||
HINT_WINDOWS_ENABLE_MESSAGELOOP :: "SDL_WINDOWS_ENABLE_MESSAGELOOP"
|
||||
HINT_WINDOWS_GAMEINPUT :: "SDL_WINDOWS_GAMEINPUT"
|
||||
HINT_WINDOWS_RAW_KEYBOARD :: "SDL_WINDOWS_RAW_KEYBOARD"
|
||||
HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS :: "SDL_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS"
|
||||
HINT_WINDOWS_FORCE_SEMAPHORE_KERNEL :: "SDL_WINDOWS_FORCE_SEMAPHORE_KERNEL"
|
||||
HINT_WINDOWS_INTRESOURCE_ICON :: "SDL_WINDOWS_INTRESOURCE_ICON"
|
||||
HINT_WINDOWS_INTRESOURCE_ICON_SMALL :: "SDL_WINDOWS_INTRESOURCE_ICON_SMALL"
|
||||
|
||||
2
vendor/sdl3/sdl3_main.odin
vendored
2
vendor/sdl3/sdl3_main.odin
vendored
@@ -3,7 +3,7 @@ package sdl3
|
||||
|
||||
import "core:c"
|
||||
|
||||
main_func :: #type proc(argc: c.int, argv: [^]cstring)
|
||||
main_func :: #type proc "c" (argc: c.int, argv: [^]cstring) -> c.int
|
||||
|
||||
@(default_calling_convention="c", link_prefix="SDL_")
|
||||
foreign lib {
|
||||
|
||||
27
vendor/sdl3/sdl3_mutex.odin
vendored
27
vendor/sdl3/sdl3_mutex.odin
vendored
@@ -1,8 +1,24 @@
|
||||
package sdl3
|
||||
|
||||
import "core:c"
|
||||
|
||||
Mutex :: struct {}
|
||||
RWLock :: struct {}
|
||||
Semaphore :: struct {}
|
||||
Condition :: struct {}
|
||||
|
||||
InitStatus :: enum c.int {
|
||||
UNINITIALIZED,
|
||||
INITIALIZING,
|
||||
INITIALIZED,
|
||||
UNINITIALIZING,
|
||||
}
|
||||
|
||||
InitState :: struct {
|
||||
status: AtomicInt,
|
||||
thread: ThreadID,
|
||||
reserved: rawptr,
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="SDL_", require_results)
|
||||
foreign lib {
|
||||
@@ -27,4 +43,15 @@ foreign lib {
|
||||
TryWaitSemaphore :: proc(sem: ^Semaphore) -> bool ---
|
||||
WaitSemaphore :: proc(sem: ^Semaphore) ---
|
||||
WaitSemaphoreTimeout :: proc(sem: ^Semaphore, timeout_ms: Sint32) ---
|
||||
|
||||
CreateCondition :: proc() -> ^Condition ---
|
||||
DestroyCondition :: proc(cond: ^Condition) ---
|
||||
SignalCondition :: proc(cond: ^Condition) ---
|
||||
BroadcastCondition :: proc(cond: ^Condition) ---
|
||||
WaitCondition :: proc(cond: ^Condition, mutex: ^Mutex) ---
|
||||
WaitConditionTimeout :: proc(cond: ^Condition, mutex: ^Mutex, timeout_ms: Sint32) -> bool ---
|
||||
|
||||
ShouldInit :: proc(state: ^InitState) -> bool ---
|
||||
ShouldQuit :: proc(state: ^InitState) -> bool ---
|
||||
SetInitialized :: proc(state: ^InitState, initialized: bool) ---
|
||||
}
|
||||
|
||||
50
vendor/sdl3/sdl3_pixels.odin
vendored
50
vendor/sdl3/sdl3_pixels.odin
vendored
@@ -75,20 +75,20 @@ DEFINE_PIXELFORMAT :: #force_inline proc "c" (type: PixelType, order: PackedOrde
|
||||
return PixelFormat(((1 << 28) | (Uint32(type) << 24) | (Uint32(order) << 20) | (Uint32(layout) << 16) | (Uint32(bits) << 8) | (Uint32(bytes) << 0)))
|
||||
}
|
||||
|
||||
@(require_results) PIXELFLAG :: proc "c" (format: PixelFormat) -> Uint32 { return ((Uint32(format) >> 28) & 0x0F) }
|
||||
@(require_results) PIXELTYPE :: proc "c" (format: PixelFormat) -> PixelType { return PixelType((Uint32(format) >> 24) & 0x0F) }
|
||||
@(require_results) PIXELORDER :: proc "c" (format: PixelFormat) -> PackedOrder { return PackedOrder((Uint32(format) >> 20) & 0x0F) }
|
||||
@(require_results) PIXELLAYOUT :: proc "c" (format: PixelFormat) -> PackedLayout { return PackedLayout((Uint32(format) >> 16) & 0x0F) }
|
||||
@(require_results) PIXELARRAYORDER :: proc "c" (format: PixelFormat) -> ArrayOrder { return ArrayOrder((Uint32(format) >> 20) & 0x0F) }
|
||||
@(require_results) PIXELFLAG :: #force_inline proc "c" (format: PixelFormat) -> Uint32 { return ((Uint32(format) >> 28) & 0x0F) }
|
||||
@(require_results) PIXELTYPE :: #force_inline proc "c" (format: PixelFormat) -> PixelType { return PixelType((Uint32(format) >> 24) & 0x0F) }
|
||||
@(require_results) PIXELORDER :: #force_inline proc "c" (format: PixelFormat) -> PackedOrder { return PackedOrder((Uint32(format) >> 20) & 0x0F) }
|
||||
@(require_results) PIXELLAYOUT :: #force_inline proc "c" (format: PixelFormat) -> PackedLayout { return PackedLayout((Uint32(format) >> 16) & 0x0F) }
|
||||
@(require_results) PIXELARRAYORDER :: #force_inline proc "c" (format: PixelFormat) -> ArrayOrder { return ArrayOrder((Uint32(format) >> 20) & 0x0F) }
|
||||
|
||||
|
||||
@(require_results)
|
||||
BITSPERPIXEL :: proc "c" (format: PixelFormat) -> Uint32 {
|
||||
BITSPERPIXEL :: #force_inline proc "c" (format: PixelFormat) -> Uint32 {
|
||||
return ISPIXELFORMAT_FOURCC(format) ? 0 : ((Uint32(format) >> 8) & 0xFF)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_INDEXED :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_INDEXED :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return (!ISPIXELFORMAT_FOURCC(format) &&
|
||||
((PIXELTYPE(format) == .INDEX1) ||
|
||||
(PIXELTYPE(format) == .INDEX2) ||
|
||||
@@ -98,7 +98,7 @@ ISPIXELFORMAT_INDEXED :: proc "c" (format: PixelFormat) -> bool {
|
||||
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_PACKED :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_PACKED :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return (!ISPIXELFORMAT_FOURCC(format) &&
|
||||
((PIXELTYPE(format) == .PACKED8) ||
|
||||
(PIXELTYPE(format) == .PACKED16) ||
|
||||
@@ -106,7 +106,7 @@ ISPIXELFORMAT_PACKED :: proc "c" (format: PixelFormat) -> bool {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_ARRAY :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_ARRAY :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return (!ISPIXELFORMAT_FOURCC(format) &&
|
||||
((PIXELTYPE(format) == .ARRAYU8) ||
|
||||
(PIXELTYPE(format) == .ARRAYU16) ||
|
||||
@@ -116,21 +116,21 @@ ISPIXELFORMAT_ARRAY :: proc "c" (format: PixelFormat) -> bool {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_10BIT :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_10BIT :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return (!ISPIXELFORMAT_FOURCC(format) &&
|
||||
((PIXELTYPE(format) == .PACKED32) &&
|
||||
(PIXELLAYOUT(format) == .LAYOUT_2101010)))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_FLOAT :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_FLOAT :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return (!ISPIXELFORMAT_FOURCC(format) &&
|
||||
((PIXELTYPE(format) == .ARRAYF16) ||
|
||||
(PIXELTYPE(format) == .ARRAYF32)))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_ALPHA :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_ALPHA :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return ((ISPIXELFORMAT_PACKED(format) &&
|
||||
((PIXELORDER(format) == .ARGB) ||
|
||||
(PIXELORDER(format) == .RGBA) ||
|
||||
@@ -144,7 +144,7 @@ ISPIXELFORMAT_ALPHA :: proc "c" (format: PixelFormat) -> bool {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISPIXELFORMAT_FOURCC :: proc "c" (format: PixelFormat) -> bool {
|
||||
ISPIXELFORMAT_FOURCC :: #force_inline proc "c" (format: PixelFormat) -> bool {
|
||||
return format != nil && PIXELFLAG(format) != 1
|
||||
}
|
||||
|
||||
@@ -369,63 +369,63 @@ ChromaLocation :: enum c.int {
|
||||
|
||||
|
||||
@(require_results)
|
||||
DEFINE_COLORSPACE :: proc "c" (type: ColorType, range: ColorRange, primaries: ColorPrimaries, transfer: TransferCharacteristics, matrix_: MatrixCoefficients, chroma: ChromaLocation) -> Colorspace {
|
||||
DEFINE_COLORSPACE :: #force_inline proc "c" (type: ColorType, range: ColorRange, primaries: ColorPrimaries, transfer: TransferCharacteristics, matrix_: MatrixCoefficients, chroma: ChromaLocation) -> Colorspace {
|
||||
return Colorspace((Uint32(type) << 28) | (Uint32(range) << 24) | (Uint32(chroma) << 20) |
|
||||
(Uint32(primaries) << 10) | (Uint32(transfer) << 5) | (Uint32(matrix_) << 0))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
COLORSPACETYPE :: proc "c" (cspace: Colorspace) -> ColorType {
|
||||
COLORSPACETYPE :: #force_inline proc "c" (cspace: Colorspace) -> ColorType {
|
||||
return ColorType((Uint32(cspace) >> 28) & 0x0F)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
COLORSPACERANGE :: proc "c" (cspace: Colorspace) -> ColorRange {
|
||||
COLORSPACERANGE :: #force_inline proc "c" (cspace: Colorspace) -> ColorRange {
|
||||
return ColorRange((Uint32(cspace) >> 24) & 0x0F)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
COLORSPACECHROMA :: proc "c" (cspace: Colorspace) -> ChromaLocation {
|
||||
COLORSPACECHROMA :: #force_inline proc "c" (cspace: Colorspace) -> ChromaLocation {
|
||||
return ChromaLocation((Uint32(cspace) >> 20) & 0x0F)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
COLORSPACEPRIMARIES :: proc "c" (cspace: Colorspace) -> ColorPrimaries {
|
||||
COLORSPACEPRIMARIES :: #force_inline proc "c" (cspace: Colorspace) -> ColorPrimaries {
|
||||
return ColorPrimaries((Uint32(cspace) >> 10) & 0x1F)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
COLORSPACETRANSFER :: proc "c" (cspace: Colorspace) -> TransferCharacteristics {
|
||||
COLORSPACETRANSFER :: #force_inline proc "c" (cspace: Colorspace) -> TransferCharacteristics {
|
||||
return TransferCharacteristics((Uint32(cspace) >> 5) & 0x1F)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
COLORSPACEMATRIX :: proc "c" (cspace: Colorspace) -> MatrixCoefficients {
|
||||
COLORSPACEMATRIX :: #force_inline proc "c" (cspace: Colorspace) -> MatrixCoefficients {
|
||||
return MatrixCoefficients(Uint32(cspace) & 0x1F)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISCOLORSPACE_MATRIX_BT601 :: proc "c" (cspace: Colorspace) -> bool {
|
||||
ISCOLORSPACE_MATRIX_BT601 :: #force_inline proc "c" (cspace: Colorspace) -> bool {
|
||||
return COLORSPACEMATRIX(cspace) == .BT601 || COLORSPACEMATRIX(cspace) == .BT470BG
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISCOLORSPACE_MATRIX_BT709 :: proc "c" (cspace: Colorspace) -> bool {
|
||||
ISCOLORSPACE_MATRIX_BT709 :: #force_inline proc "c" (cspace: Colorspace) -> bool {
|
||||
return COLORSPACEMATRIX(cspace) == .BT709
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISCOLORSPACE_MATRIX_BT2020_NCL :: proc "c" (cspace: Colorspace) -> bool {
|
||||
ISCOLORSPACE_MATRIX_BT2020_NCL :: #force_inline proc "c" (cspace: Colorspace) -> bool {
|
||||
return COLORSPACEMATRIX(cspace) == .BT2020_NCL
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISCOLORSPACE_LIMITED_RANGE :: proc "c" (cspace: Colorspace) -> bool {
|
||||
ISCOLORSPACE_LIMITED_RANGE :: #force_inline proc "c" (cspace: Colorspace) -> bool {
|
||||
return COLORSPACERANGE(cspace) != .FULL
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
ISCOLORSPACE_FULL_RANGE :: proc "c" (cspace: Colorspace) -> bool {
|
||||
ISCOLORSPACE_FULL_RANGE :: #force_inline proc "c" (cspace: Colorspace) -> bool {
|
||||
return COLORSPACERANGE(cspace) == .FULL
|
||||
}
|
||||
|
||||
|
||||
25
vendor/sdl3/sdl3_rect.odin
vendored
25
vendor/sdl3/sdl3_rect.odin
vendored
@@ -24,38 +24,51 @@ RectToFRect :: #force_inline proc "c" (rect: Rect, frect: ^FRect) {
|
||||
|
||||
|
||||
@(require_results)
|
||||
PointInRect :: proc "c" (p: Point, r: Rect) -> bool {
|
||||
PointInRect :: #force_inline proc "c" (p: Point, r: Rect) -> bool {
|
||||
return ( (p.x >= r.x) && (p.x < (r.x + r.w)) &&
|
||||
(p.y >= r.y) && (p.y < (r.y + r.h)) )
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
PointInRectFloat :: proc "c" (p: FPoint, r: FRect) -> bool {
|
||||
PointInRectFloat :: #force_inline proc "c" (p: FPoint, r: FRect) -> bool {
|
||||
return ( (p.x >= r.x) && (p.x <= (r.x + r.w)) &&
|
||||
(p.y >= r.y) && (p.y <= (r.y + r.h)) )
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
RectEmpty :: proc "c" (r: Rect) -> bool {
|
||||
RectEmpty :: #force_inline proc "c" (r: Rect) -> bool {
|
||||
return r.w <= 0 || r.h <= 0
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
RectEqual :: proc "c" (a, b: Rect) -> bool {
|
||||
RectEqual :: #force_inline proc "c" (a, b: Rect) -> bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
RectsEqualEpsilon :: #force_inline proc "c" (a, b: FRect, epsilon: f32) -> bool {
|
||||
return abs(a.x - b.x) <= epsilon &&
|
||||
abs(a.y - b.y) <= epsilon &&
|
||||
abs(a.w - b.w) <= epsilon &&
|
||||
abs(a.h - b.h) <= epsilon
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
RectsEqualFloat :: #force_inline proc "c" (a, b: FRect) -> bool {
|
||||
return RectsEqualEpsilon(a, b, FLT_EPSILON)
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="SDL_", require_results)
|
||||
foreign lib {
|
||||
HasRectIntersection :: proc(#by_ptr A, B: Rect) -> bool ---
|
||||
GetRectIntersection :: proc(#by_ptr A, B: Rect, result: ^Rect) -> bool ---
|
||||
GetRectUnion :: proc(#by_ptr A, B: Rect, result: ^Rect) -> bool ---
|
||||
GetRectEnclosingPoints :: proc(points: [^]Point, count: c.int, #by_ptr clip: Rect, result: ^Rect) -> bool ---
|
||||
GetRectEnclosingPoints :: proc(points: [^]Point, count: c.int, clip: Maybe(^Rect), result: ^Rect) -> bool ---
|
||||
GetRectAndLineIntersection :: proc(#by_ptr rect: Rect, X1, Y1, X2, Y2: ^c.int) -> bool ---
|
||||
HasRectIntersectionFloat :: proc(#by_ptr A, B: FRect) -> bool ---
|
||||
GetRectIntersectionFloat :: proc(#by_ptr A, B: FRect, result: ^FRect) -> bool ---
|
||||
GetRectUnionFloat :: proc(#by_ptr A, B: FRect, result: ^FRect) -> bool ---
|
||||
GetRectEnclosingPointsFloat :: proc(points: [^]FPoint, count: c.int, #by_ptr clip: FRect, result: ^FRect) -> bool ---
|
||||
GetRectEnclosingPointsFloat :: proc(points: [^]FPoint, count: c.int, clip: Maybe(^FRect), result: ^FRect) -> bool ---
|
||||
GetRectAndLineIntersectionFloat :: proc(#by_ptr rect: FRect, X1, Y1, X2, Y2: ^f32) -> bool ---
|
||||
}
|
||||
6
vendor/sdl3/sdl3_render.odin
vendored
6
vendor/sdl3/sdl3_render.odin
vendored
@@ -240,8 +240,8 @@ foreign lib {
|
||||
RenderTextureTiled :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), scale: f32, dstrect: Maybe(^FRect)) -> bool ---
|
||||
RenderTexture9Grid :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), left_width, right_width, top_height, bottom_height: f32, scale: f32, dstrect: Maybe(^FRect)) -> bool ---
|
||||
RenderTexture9GridTiled :: proc(renderer: ^Renderer, texture: ^Texture, srcrect: Maybe(^FRect), left_width, right_width, top_height, bottom_height: f32, scale: f32, dstrect: Maybe(^FRect), tileScale: f32) -> bool ---
|
||||
RenderGeometry :: proc(renderer: ^Renderer, texture: ^Texture, vertices: [^]Vertex, num_vertices: c.int, indices: [^]c.int, num_indices: c.int) -> bool ---
|
||||
RenderGeometryRaw :: proc(renderer: ^Renderer, texture: ^Texture, xy: [^]f32, xy_stride: c.int, color: [^]FColor, color_stride: c.int, uv: [^]f32, uv_stride: c.int, num_vertices: c.int, indices: rawptr, num_indices: c.int, size_indices: c.int) -> bool ---
|
||||
RenderGeometry :: proc(renderer: ^Renderer, texture: Maybe(^Texture), vertices: [^]Vertex, num_vertices: c.int, indices: [^]c.int, num_indices: c.int) -> bool ---
|
||||
RenderGeometryRaw :: proc(renderer: ^Renderer, texture: Maybe(^Texture), xy: [^]f32, xy_stride: c.int, color: [^]FColor, color_stride: c.int, uv: [^]f32, uv_stride: c.int, num_vertices: c.int, indices: rawptr, num_indices: c.int, size_indices: c.int) -> bool ---
|
||||
SetRenderTextureAddressMode :: proc(renderer: ^Renderer, u_mode, v_mode: TextureAddressMode) -> bool ---
|
||||
GetRenderTextureAddressMode :: proc(renderer: ^Renderer, u_mode, v_mode: ^TextureAddressMode) -> bool ---
|
||||
RenderPresent :: proc(renderer: ^Renderer) -> bool ---
|
||||
@@ -276,5 +276,5 @@ foreign lib {
|
||||
CreateGPURenderState :: proc(renderer: ^Renderer, #by_ptr createinfo: GPURenderStateCreateInfo) -> ^GPURenderState ---
|
||||
SetGPURenderStateFragmentUniforms :: proc(state: ^GPURenderState, slot_index: Uint32, data: rawptr, length: Uint32) -> bool ---
|
||||
SetGPURenderState :: proc(renderer: ^Renderer, state: ^GPURenderState) -> bool ---
|
||||
DestroyGPURenderState :: proc(renderer: ^Renderer) ---
|
||||
DestroyGPURenderState :: proc(renderer: ^GPURenderState) ---
|
||||
}
|
||||
|
||||
9
vendor/sdl3/sdl3_system.odin
vendored
9
vendor/sdl3/sdl3_system.odin
vendored
@@ -6,7 +6,7 @@ import "core:c"
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
WindowsMessageHook :: #type proc(userdata: rawptr, msg: ^win32.MSG) -> bool
|
||||
WindowsMessageHook :: #type proc "c" (userdata: rawptr, msg: ^win32.MSG) -> bool
|
||||
|
||||
@(default_calling_convention="c", link_prefix="SDL_")
|
||||
foreign lib {
|
||||
@@ -46,6 +46,11 @@ foreign lib {
|
||||
|
||||
RequestAndroidPermissionCallback :: #type proc "c" (userdata: rawptr, permission: cstring, granted: bool)
|
||||
|
||||
AndroidExternalStorageFlags :: distinct bit_set[AndroidExternalStorageFlag; Uint32]
|
||||
AndroidExternalStorageFlag :: enum Uint32 {
|
||||
Read,
|
||||
Write,
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="SDL_", require_results)
|
||||
foreign lib {
|
||||
@@ -56,7 +61,7 @@ foreign lib {
|
||||
IsDeXMode :: proc() -> bool ---
|
||||
SendAndroidBackButton :: proc() ---
|
||||
GetAndroidInternalStoragePath :: proc() -> cstring ---
|
||||
GetAndroidExternalStorageState :: proc() -> Uint32 ---
|
||||
GetAndroidExternalStorageState :: proc() -> AndroidExternalStorageFlags ---
|
||||
GetAndroidExternalStoragePath :: proc() -> cstring ---
|
||||
GetAndroidCachePath :: proc() -> cstring ---
|
||||
RequestAndroidPermission :: proc(permission: cstring, cb: RequestAndroidPermissionCallback, userdata: rawptr) -> bool ---
|
||||
|
||||
5
vendor/sdl3/sdl3_video.odin
vendored
5
vendor/sdl3/sdl3_video.odin
vendored
@@ -151,7 +151,7 @@ EGLSurface :: distinct rawptr
|
||||
EGLAttrib :: distinct uintptr
|
||||
EGLint :: distinct c.int
|
||||
|
||||
EGLAttribArrayCallback :: #type proc "c" (userdata: rawptr) -> ^EGLint
|
||||
EGLAttribArrayCallback :: #type proc "c" (userdata: rawptr) -> [^]EGLint
|
||||
EGLIntArrayCallback :: #type proc "c" (userdata: rawptr, display: EGLDisplay, config: EGLConfig) -> [^]EGLint
|
||||
|
||||
GLAttr :: enum c.int {
|
||||
@@ -256,9 +256,12 @@ GL_CONTEXT_RESET_LOSE_CONTEXT :: GLContextResetNotification{.LOSE_CONTEXT}
|
||||
|
||||
PROP_DISPLAY_HDR_ENABLED_BOOLEAN :: "SDL.display.HDR_enabled"
|
||||
PROP_DISPLAY_KMSDRM_PANEL_ORIENTATION_NUMBER :: "SDL.display.KMSDRM.panel_orientation"
|
||||
PROP_DISPLAY_WAYLAND_WL_OUTPUT_POINTER :: "SDL.display.wayland.wl_output"
|
||||
PROP_DISPLAY_WINDOWS_HMONITOR_POINTER :: "SDL.display.windows.hmonitor"
|
||||
|
||||
PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN :: "SDL.window.create.always_on_top"
|
||||
PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN :: "SDL.window.create.borderless"
|
||||
PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN :: "SDL.window.create.constrain_popup"
|
||||
PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN :: "SDL.window.create.focusable"
|
||||
PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN :: "SDL.window.create.external_graphics_context"
|
||||
PROP_WINDOW_CREATE_FLAGS_NUMBER :: "SDL.window.create.flags"
|
||||
|
||||
20
vendor/stb/truetype/stb_truetype.odin
vendored
20
vendor/stb/truetype/stb_truetype.odin
vendored
@@ -111,7 +111,7 @@ pack_range :: struct {
|
||||
first_unicode_codepoint_in_range: c.int,
|
||||
array_of_unicode_codepoints: [^]rune,
|
||||
num_chars: c.int,
|
||||
chardata_for_range: ^packedchar,
|
||||
chardata_for_range: [^]packedchar,
|
||||
_, _: u8, // used internally to store oversample info
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ foreign stbtt {
|
||||
// bilinear filtering).
|
||||
//
|
||||
// Returns 0 on failure, 1 on success.
|
||||
PackBegin :: proc(spc: ^pack_context, pixels: [^]byte, width, height, stride_in_bytes, padding: c.int, alloc_context: rawptr) -> c.int ---
|
||||
PackBegin :: proc(spc: ^pack_context, pixels: [^]byte, width, height, stride_in_bytes, padding: c.int, alloc_context: rawptr) -> b32 ---
|
||||
|
||||
// Cleans up the packing context and frees all memory.
|
||||
PackEnd :: proc(spc: ^pack_context) ---
|
||||
@@ -155,13 +155,17 @@ foreign stbtt {
|
||||
// and pass that result as 'font_size':
|
||||
// ..., 20 , ... // font max minus min y is 20 pixels tall
|
||||
// ..., POINT_SIZE(20), ... // 'M' is 20 pixels tall
|
||||
PackFontRange :: proc(spc: ^pack_context, fontdata: [^]byte, font_index: c.int, font_size: f32, first_unicode_char_in_range, num_chars_in_range: c.int, chardata_for_range: ^packedchar) -> c.int ---
|
||||
//
|
||||
// Returns 0 on failure, 1 on success.
|
||||
PackFontRange :: proc(spc: ^pack_context, fontdata: [^]byte, font_index: c.int, font_size: f32, first_unicode_char_in_range, num_chars_in_range: c.int, chardata_for_range: [^]packedchar) -> b32 ---
|
||||
|
||||
// Creates character bitmaps from multiple ranges of characters stored in
|
||||
// ranges. This will usually create a better-packed bitmap than multiple
|
||||
// calls to stbtt_PackFontRange. Note that you can call this multiple
|
||||
// times within a single PackBegin/PackEnd.
|
||||
PackFontRanges :: proc(spc: ^pack_context, fontdata: [^]byte, font_index: c.int, ranges: [^]pack_range, num_ranges: c.int) -> c.int ---
|
||||
//
|
||||
// Returns 0 on failure, 1 on success.
|
||||
PackFontRanges :: proc(spc: ^pack_context, fontdata: [^]byte, font_index: c.int, ranges: [^]pack_range, num_ranges: c.int) -> b32 ---
|
||||
|
||||
// Oversampling a font increases the quality by allowing higher-quality subpixel
|
||||
// positioning, and is especially valuable at smaller text sizes.
|
||||
@@ -201,9 +205,13 @@ foreign stbtt {
|
||||
// then call RenderIntoRects repeatedly. This may result in a
|
||||
// better packing than calling PackFontRanges multiple times
|
||||
// (or it may not).
|
||||
PackFontRangesGatherRects :: proc(spc: ^pack_context, info: ^fontinfo, ranges: ^pack_range, num_ranges: c.int, rects: [^]stbrp.Rect) -> c.int ---
|
||||
//
|
||||
// Returns the number of rects which were not skipped.
|
||||
// PackSetSkipMissingCodepoints controls this behavior.
|
||||
PackFontRangesGatherRects :: proc(spc: ^pack_context, info: ^fontinfo, ranges: [^]pack_range, num_ranges: c.int, rects: [^]stbrp.Rect) -> c.int ---
|
||||
PackFontRangesPackRects :: proc(spc: ^pack_context, rects: [^]stbrp.Rect, num_rects: c.int) ---
|
||||
PackFontRangesRenderIntoRects :: proc(spc: ^pack_context, info: ^fontinfo, ranges: ^pack_range, num_ranges: c.int, rects: [^]stbrp.Rect) -> c.int ---
|
||||
// Returns 0 on failure, 1 on success.
|
||||
PackFontRangesRenderIntoRects :: proc(spc: ^pack_context, info: ^fontinfo, ranges: [^]pack_range, num_ranges: c.int, rects: [^]stbrp.Rect) -> b32 ---
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user