Merge branch 'odin-lang:master' into raylib5

This commit is contained in:
Michael
2023-11-26 00:00:47 -07:00
committed by GitHub
53 changed files with 7090 additions and 369 deletions
+1
View File
@@ -110,6 +110,7 @@ if %errorlevel% neq 0 goto end_of_build
call build_vendor.bat call build_vendor.bat
if %errorlevel% neq 0 goto end_of_build if %errorlevel% neq 0 goto end_of_build
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
if %release_mode% EQU 0 odin run examples/demo if %release_mode% EQU 0 odin run examples/demo
del *.obj > NUL 2> NUL del *.obj > NUL 2> NUL
+2
View File
@@ -27,11 +27,13 @@ error() {
if [ -z "$LLVM_CONFIG" ]; then if [ -z "$LLVM_CONFIG" ]; then
# darwin, linux, openbsd # darwin, linux, openbsd
if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17" if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17"
elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14"
elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13" elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13"
elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12"
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11" elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
# freebsd # freebsd
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17" elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17"
elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config-14"
elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13" elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13"
elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12"
elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11" elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11"
+2
View File
@@ -2,6 +2,8 @@ package libc
import "core:c" import "core:c"
#assert(!ODIN_NO_CRT, `"core:c/libc" cannot be imported when '-no-crt' is used`)
char :: c.char // assuming -funsigned-char char :: c.char // assuming -funsigned-char
schar :: c.schar schar :: c.schar
+7
View File
@@ -162,7 +162,14 @@ type_is_matrix :: proc($T: typeid) -> bool ---
type_has_nil :: proc($T: typeid) -> bool --- type_has_nil :: proc($T: typeid) -> bool ---
type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool ---
type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) ---
type_union_tag_type :: proc($T: typeid) -> typeid where type_is_union(T) ---
type_union_tag_offset :: proc($T: typeid) -> uintptr where type_is_union(T) ---
type_union_base_tag_value :: proc($T: typeid) -> int where type_is_union(U) ---
type_union_variant_count :: proc($T: typeid) -> int where type_is_union(T) ---
type_variant_type_of :: proc($T: typeid, $index: int) -> typeid where type_is_union(T) ---
type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) ---
type_has_field :: proc($T: typeid, $name: string) -> bool --- type_has_field :: proc($T: typeid, $name: string) -> bool ---
type_field_type :: proc($T: typeid, $name: string) -> typeid --- type_field_type :: proc($T: typeid, $name: string) -> typeid ---
+2 -2
View File
@@ -60,9 +60,9 @@ Logger_Proc :: runtime.Logger_Proc
/* /*
Logger :: struct { Logger :: struct {
procedure: Logger_Proc, procedure: Logger_Proc,
data: rawptr, data: rawptr,
lowest_level: Level, lowest_level: Level,
options: Logger_Options, options: Logger_Options,
} }
*/ */
Logger :: runtime.Logger Logger :: runtime.Logger
+11 -11
View File
@@ -2312,17 +2312,17 @@ F32_NORMALIZE :: 0
F32_RADIX :: 2 F32_RADIX :: 2
F32_ROUNDS :: 1 F32_ROUNDS :: 1
F64_DIG :: 15 // # of decimal digits of precision F64_DIG :: 15 // Number of representable decimal digits.
F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0 F64_EPSILON :: 2.2204460492503131e-016 // Smallest number such that `1.0 + F64_EPSILON != 1.0`.
F64_MANT_DIG :: 53 // # of bits in mantissa F64_MANT_DIG :: 53 // Number of bits in the mantissa.
F64_MAX :: 1.7976931348623158e+308 // max value F64_MAX :: 1.7976931348623158e+308 // Maximum representable value.
F64_MAX_10_EXP :: 308 // max decimal exponent F64_MAX_10_EXP :: 308 // Maximum base-10 exponent yielding normalized value.
F64_MAX_EXP :: 1024 // max binary exponent F64_MAX_EXP :: 1024 // One greater than the maximum possible base-2 exponent yielding normalized value.
F64_MIN :: 2.2250738585072014e-308 // min positive value F64_MIN :: 2.2250738585072014e-308 // Minimum positive normalized value.
F64_MIN_10_EXP :: -307 // min decimal exponent F64_MIN_10_EXP :: -307 // Minimum base-10 exponent yielding normalized value.
F64_MIN_EXP :: -1021 // min binary exponent F64_MIN_EXP :: -1021 // One greater than the minimum possible base-2 exponent yielding normalized value.
F64_RADIX :: 2 // exponent radix F64_RADIX :: 2 // Exponent radix.
F64_ROUNDS :: 1 // addition rounding: near F64_ROUNDS :: 1 // Addition rounding: near.
F16_MASK :: 0x1f F16_MASK :: 0x1f
+37 -2
View File
@@ -148,7 +148,29 @@ recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_en
return _recv_udp(socket, buf) return _recv_udp(socket, buf)
} }
recv :: proc{recv_tcp, recv_udp} /*
Receive data from into a buffer from any socket.
Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it
will always return `nil`.
*/
recv_any :: proc(socket: Any_Socket, buf: []byte) -> (
bytes_read: int,
remote_endpoint: Maybe(Endpoint),
err: Network_Error,
) {
switch socktype in socket {
case TCP_Socket:
bytes_read, err := recv_tcp(socktype, buf)
return bytes_read, nil, err
case UDP_Socket:
bytes_read, endpoint, err := recv_udp(socktype, buf)
return bytes_read, endpoint, err
case: panic("Not supported")
}
}
recv :: proc{recv_tcp, recv_udp, recv_any}
/* /*
Repeatedly sends data until the entire buffer is sent. Repeatedly sends data until the entire buffer is sent.
@@ -168,7 +190,20 @@ send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_writte
return _send_udp(socket, buf, to) return _send_udp(socket, buf, to)
} }
send :: proc{send_tcp, send_udp} send_any :: proc(socket: Any_Socket, buf: []byte, to: Maybe(Endpoint) = nil) -> (
bytes_written: int,
err: Network_Error,
) {
switch socktype in socket {
case TCP_Socket:
return send_tcp(socktype, buf)
case UDP_Socket:
return send_udp(socktype, buf, to.(Endpoint))
case: panic("Not supported")
}
}
send :: proc{send_tcp, send_udp, send_any}
shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) {
return _shutdown(socket, manner) return _shutdown(socket, manner)
+1 -1
View File
@@ -125,7 +125,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (An
} }
@(private) @(private)
_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (tcp_sock: TCP_Socket, err: Network_Error) { _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (TCP_Socket, Network_Error) {
errno: linux.Errno errno: linux.Errno
if endpoint.port == 0 { if endpoint.port == 0 {
return 0, .Port_Required return 0, .Port_Required
+10 -1
View File
@@ -7,7 +7,7 @@ import "core:reflect"
import "core:odin/tokenizer" import "core:odin/tokenizer"
_ :: intrinsics _ :: intrinsics
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { new_from_positions :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
n, _ := mem.new(T) n, _ := mem.new(T)
n.pos = pos n.pos = pos
n.end = end n.end = end
@@ -23,6 +23,15 @@ new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
return n return n
} }
new_from_pos_and_end_node :: proc($T: typeid, pos: tokenizer.Pos, end: ^Node) -> ^T {
return new(T, pos, end != nil ? end.end : pos)
}
new :: proc {
new_from_positions,
new_from_pos_and_end_node,
}
clone :: proc{ clone :: proc{
clone_node, clone_node,
clone_expr, clone_expr,
+49 -45
View File
@@ -787,7 +787,10 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
} }
} }
end := body.end end: tokenizer.Pos
if body != nil {
end = body.end
}
if else_stmt != nil { if else_stmt != nil {
end = else_stmt.end end = else_stmt.end
} }
@@ -850,7 +853,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body = parse_body(p) body = parse_body(p)
} }
range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end) range_stmt := ast.new(ast.Range_Stmt, tok.pos, body)
range_stmt.for_pos = tok.pos range_stmt.for_pos = tok.pos
range_stmt.in_pos = in_tok.pos range_stmt.in_pos = in_tok.pos
range_stmt.expr = rhs range_stmt.expr = rhs
@@ -910,7 +913,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
rhs = assign_stmt.rhs[0] rhs = assign_stmt.rhs[0]
} }
range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end) range_stmt := ast.new(ast.Range_Stmt, tok.pos, body)
range_stmt.for_pos = tok.pos range_stmt.for_pos = tok.pos
range_stmt.vals = vals range_stmt.vals = vals
range_stmt.in_pos = assign_stmt.op.pos range_stmt.in_pos = assign_stmt.op.pos
@@ -920,7 +923,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
} }
cond_expr := convert_stmt_to_expr(p, cond, "boolean expression") cond_expr := convert_stmt_to_expr(p, cond, "boolean expression")
for_stmt := ast.new(ast.For_Stmt, tok.pos, body.end) for_stmt := ast.new(ast.For_Stmt, tok.pos, body)
for_stmt.for_pos = tok.pos for_stmt.for_pos = tok.pos
for_stmt.init = init for_stmt.init = init
for_stmt.cond = cond_expr for_stmt.cond = cond_expr
@@ -976,7 +979,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
lhs[0] = new_blank_ident(p, tok.pos) lhs[0] = new_blank_ident(p, tok.pos)
rhs[0] = parse_expr(p, true) rhs[0] = parse_expr(p, true)
as := ast.new(ast.Assign_Stmt, tok.pos, rhs[0].end) as := ast.new(ast.Assign_Stmt, tok.pos, rhs[0])
as.lhs = lhs as.lhs = lhs
as.op = in_tok as.op = in_tok
as.rhs = rhs as.rhs = rhs
@@ -1010,14 +1013,14 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body.stmts = clauses[:] body.stmts = clauses[:]
if is_type_switch { if is_type_switch {
ts := ast.new(ast.Type_Switch_Stmt, tok.pos, body.end) ts := ast.new(ast.Type_Switch_Stmt, tok.pos, body)
ts.tag = tag ts.tag = tag
ts.body = body ts.body = body
ts.switch_pos = tok.pos ts.switch_pos = tok.pos
return ts return ts
} else { } else {
cond := convert_stmt_to_expr(p, tag, "switch expression") cond := convert_stmt_to_expr(p, tag, "switch expression")
ts := ast.new(ast.Switch_Stmt, tok.pos, body.end) ts := ast.new(ast.Switch_Stmt, tok.pos, body)
ts.init = init ts.init = init
ts.cond = cond ts.cond = cond
ts.body = body ts.body = body
@@ -1044,7 +1047,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
if p.curr_tok.kind == .Eq { if p.curr_tok.kind == .Eq {
eq := expect_token(p, .Eq) eq := expect_token(p, .Eq)
value := parse_value(p) value := parse_value(p)
fv := ast.new(ast.Field_Value, elem.pos, value.end) fv := ast.new(ast.Field_Value, elem.pos, value)
fv.field = elem fv.field = elem
fv.sep = eq.pos fv.sep = eq.pos
fv.value = value fv.value = value
@@ -1137,7 +1140,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl
body.stmts = decls[:] body.stmts = decls[:]
body.close = close.pos body.close = close.pos
decl := ast.new(ast.Foreign_Block_Decl, tok.pos, body.end) decl := ast.new(ast.Foreign_Block_Decl, tok.pos, body)
decl.docs = docs decl.docs = docs
decl.tok = tok decl.tok = tok
decl.foreign_library = foreign_library decl.foreign_library = foreign_library
@@ -1248,7 +1251,7 @@ parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast
return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok)) return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok))
} }
range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body.end) range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body)
range_stmt.inline_pos = inline_tok.pos range_stmt.inline_pos = inline_tok.pos
range_stmt.for_pos = for_tok.pos range_stmt.for_pos = for_tok.pos
range_stmt.val0 = val0 range_stmt.val0 = val0
@@ -1304,7 +1307,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case ^ast.Return_Stmt: case ^ast.Return_Stmt:
error(p, s.pos, "you cannot defer a return statement") error(p, s.pos, "you cannot defer a return statement")
} }
ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end) ds := ast.new(ast.Defer_Stmt, tok.pos, stmt)
ds.stmt = stmt ds.stmt = stmt
return ds return ds
@@ -1341,8 +1344,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident { if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident {
label = parse_ident(p) label = parse_ident(p)
} }
end := label.end if label != nil else end_pos(tok) s := ast.new(ast.Branch_Stmt, tok.pos, label)
s := ast.new(ast.Branch_Stmt, tok.pos, end)
s.tok = tok s.tok = tok
s.label = label s.label = label
expect_semicolon(p, s) expect_semicolon(p, s)
@@ -1366,7 +1368,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if p.curr_tok.kind != .Colon { if p.curr_tok.kind != .Colon {
end := list[len(list)-1] end := list[len(list)-1]
expect_semicolon(p, end) expect_semicolon(p, end)
us := ast.new(ast.Using_Stmt, tok.pos, end.end) us := ast.new(ast.Using_Stmt, tok.pos, end)
us.list = list us.list = list
return us return us
} }
@@ -1416,13 +1418,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
bd.tok = tok bd.tok = tok
bd.name = name bd.name = name
ce := parse_call_expr(p, bd) ce := parse_call_expr(p, bd)
es := ast.new(ast.Expr_Stmt, ce.pos, ce.end) es := ast.new(ast.Expr_Stmt, ce.pos, ce)
es.expr = ce es.expr = ce
return es return es
case "force_inline", "force_no_inline": case "force_inline", "force_no_inline":
expr := parse_inlining_operand(p, true, tag) expr := parse_inlining_operand(p, true, tag)
es := ast.new(ast.Expr_Stmt, expr.pos, expr.end) es := ast.new(ast.Expr_Stmt, expr.pos, expr)
es.expr = expr es.expr = expr
return es return es
case "unroll": case "unroll":
@@ -1444,7 +1446,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag)) return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag))
case: case:
stmt := parse_stmt(p) stmt := parse_stmt(p)
te := ast.new(ast.Tag_Stmt, tok.pos, stmt.pos) end := stmt.pos if stmt != nil else end_pos(tok)
te := ast.new(ast.Tag_Stmt, tok.pos, end)
te.op = tok te.op = tok
te.name = name te.name = name
te.stmt = stmt te.stmt = stmt
@@ -1572,7 +1575,7 @@ convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
error(p, stmt.pos, "expected a non-empty statement") error(p, stmt.pos, "expected a non-empty statement")
} }
bs := ast.new(ast.Block_Stmt, stmt.pos, stmt.end) bs := ast.new(ast.Block_Stmt, stmt.pos, stmt)
bs.open = stmt.pos bs.open = stmt.pos
bs.stmts = make([]^ast.Stmt, 1) bs.stmts = make([]^ast.Stmt, 1)
bs.stmts[0] = stmt bs.stmts[0] = stmt
@@ -1741,7 +1744,7 @@ parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr {
error(p, tok.pos, "variadic field missing type after '..'") error(p, tok.pos, "variadic field missing type after '..'")
type = ast.new(ast.Bad_Expr, tok.pos, end_pos(tok)) type = ast.new(ast.Bad_Expr, tok.pos, end_pos(tok))
} }
e := ast.new(ast.Ellipsis, type.pos, type.end) e := ast.new(ast.Ellipsis, type.pos, type)
e.expr = type e.expr = type
return e return e
} }
@@ -1808,7 +1811,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr {
if is_blank_ident(ident) { if is_blank_ident(ident) {
error(p, ident.pos, "invalid polymorphic type definition with a blank identifier") error(p, ident.pos, "invalid polymorphic type definition with a blank identifier")
} }
poly_name := ast.new(ast.Poly_Type, tok.pos, ident.end) poly_name := ast.new(ast.Poly_Type, tok.pos, ident)
poly_name.type = ident poly_name.type = ident
append(&list, poly_name) append(&list, poly_name)
} else { } else {
@@ -2154,7 +2157,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
e.inlining = pi e.inlining = pi
case: case:
error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text) error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text)
return ast.new(ast.Bad_Expr, tok.pos, expr.end) return ast.new(ast.Bad_Expr, tok.pos, expr)
} }
return expr return expr
} }
@@ -2204,7 +2207,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Distinct: case .Distinct:
tok := advance_token(p) tok := advance_token(p)
type := parse_type(p) type := parse_type(p)
dt := ast.new(ast.Distinct_Type, tok.pos, type.end) dt := ast.new(ast.Distinct_Type, tok.pos, type)
dt.tok = tok.kind dt.tok = tok.kind
dt.type = type dt.type = type
return dt return dt
@@ -2215,7 +2218,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
switch name.text { switch name.text {
case "type": case "type":
type := parse_type(p) type := parse_type(p)
hp := ast.new(ast.Helper_Type, tok.pos, type.end) hp := ast.new(ast.Helper_Type, tok.pos, type)
hp.tok = tok.kind hp.tok = tok.kind
hp.type = type hp.type = type
return hp return hp
@@ -2319,7 +2322,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag_call := parse_call_expr(p, tag) tag_call := parse_call_expr(p, tag)
type := parse_type(p) type := parse_type(p)
rt := ast.new(ast.Relative_Type, tok.pos, type.end) rt := ast.new(ast.Relative_Type, tok.pos, type)
rt.tag = tag_call rt.tag = tag_call
rt.type = type rt.type = type
return rt return rt
@@ -2328,7 +2331,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return parse_inlining_operand(p, lhs, name) return parse_inlining_operand(p, lhs, name)
case: case:
expr := parse_expr(p, lhs) expr := parse_expr(p, lhs)
te := ast.new(ast.Tag_Expr, tok.pos, expr.pos) end := expr.pos if expr != nil else end_pos(tok)
te := ast.new(ast.Tag_Expr, tok.pos, end)
te.op = tok te.op = tok
te.name = name.text te.name = name.text
te.expr = expr te.expr = expr
@@ -2456,7 +2460,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Pointer: case .Pointer:
tok := expect_token(p, .Pointer) tok := expect_token(p, .Pointer)
elem := parse_type(p) elem := parse_type(p)
ptr := ast.new(ast.Pointer_Type, tok.pos, elem.end) ptr := ast.new(ast.Pointer_Type, tok.pos, elem)
ptr.pointer = tok.pos ptr.pointer = tok.pos
ptr.elem = elem ptr.elem = elem
return ptr return ptr
@@ -2470,7 +2474,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Pointer) tok := expect_token(p, .Pointer)
close := expect_token(p, .Close_Bracket) close := expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
t := ast.new(ast.Multi_Pointer_Type, open.pos, elem.end) t := ast.new(ast.Multi_Pointer_Type, open.pos, elem)
t.open = open.pos t.open = open.pos
t.pointer = tok.pos t.pointer = tok.pos
t.close = close.pos t.close = close.pos
@@ -2480,7 +2484,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Dynamic) tok := expect_token(p, .Dynamic)
close := expect_token(p, .Close_Bracket) close := expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
da := ast.new(ast.Dynamic_Array_Type, open.pos, elem.end) da := ast.new(ast.Dynamic_Array_Type, open.pos, elem)
da.open = open.pos da.open = open.pos
da.dynamic_pos = tok.pos da.dynamic_pos = tok.pos
da.close = close.pos da.close = close.pos
@@ -2500,7 +2504,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
} }
close := expect_token(p, .Close_Bracket) close := expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
at := ast.new(ast.Array_Type, open.pos, elem.end) at := ast.new(ast.Array_Type, open.pos, elem)
at.open = open.pos at.open = open.pos
at.len = count at.len = count
at.close = close.pos at.close = close.pos
@@ -2514,7 +2518,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
expect_token(p, .Close_Bracket) expect_token(p, .Close_Bracket)
value := parse_type(p) value := parse_type(p)
mt := ast.new(ast.Map_Type, tok.pos, value.end) mt := ast.new(ast.Map_Type, tok.pos, value)
mt.tok_pos = tok.pos mt.tok_pos = tok.pos
mt.key = key mt.key = key
mt.value = value mt.value = value
@@ -2755,7 +2759,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
expect_token(p, .Close_Bracket) expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
mt := ast.new(ast.Matrix_Type, tok.pos, elem.end) mt := ast.new(ast.Matrix_Type, tok.pos, elem)
mt.tok_pos = tok.pos mt.tok_pos = tok.pos
mt.row_count = row_count mt.row_count = row_count
mt.column_count = column_count mt.column_count = column_count
@@ -2893,7 +2897,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
eq := expect_token(p, .Eq) eq := expect_token(p, .Eq)
value := parse_value(p) value := parse_value(p)
fv := ast.new(ast.Field_Value, elem.pos, value.end) fv := ast.new(ast.Field_Value, elem.pos, value)
fv.field = elem fv.field = elem
fv.sep = eq.pos fv.sep = eq.pos
fv.value = value fv.value = value
@@ -2962,7 +2966,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
} }
value := parse_value(p) value := parse_value(p)
fv := ast.new(ast.Field_Value, arg.pos, value.end) fv := ast.new(ast.Field_Value, arg.pos, value)
fv.field = arg fv.field = arg
fv.sep = eq.pos fv.sep = eq.pos
fv.value = value fv.value = value
@@ -2993,7 +2997,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
o := ast.unparen_expr(operand) o := ast.unparen_expr(operand)
if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end) sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce)
sce.expr = o sce.expr = o
sce.call = ce sce.call = ce
return sce return sce
@@ -3101,7 +3105,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case .Ident: case .Ident:
field := parse_ident(p) field := parse_ident(p)
sel := ast.new(ast.Selector_Expr, operand.pos, field.end) sel := ast.new(ast.Selector_Expr, operand.pos, field)
sel.expr = operand sel.expr = operand
sel.op = tok sel.op = tok
sel.field = field sel.field = field
@@ -3127,7 +3131,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
type.op = question type.op = question
type.expr = nil type.expr = nil
ta := ast.new(ast.Type_Assertion, operand.pos, type.end) ta := ast.new(ast.Type_Assertion, operand.pos, type)
ta.expr = operand ta.expr = operand
ta.type = type ta.type = type
@@ -3145,7 +3149,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case .Ident: case .Ident:
field := parse_ident(p) field := parse_ident(p)
sel := ast.new(ast.Selector_Expr, operand.pos, field.end) sel := ast.new(ast.Selector_Expr, operand.pos, field)
sel.expr = operand sel.expr = operand
sel.op = tok sel.op = tok
sel.field = field sel.field = field
@@ -3225,7 +3229,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
close := expect_token(p, .Close_Paren) close := expect_token(p, .Close_Paren)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
tc := ast.new(ast.Type_Cast, tok.pos, expr.end) tc := ast.new(ast.Type_Cast, tok.pos, expr)
tc.tok = tok tc.tok = tok
tc.open = open.pos tc.open = open.pos
tc.type = type tc.type = type
@@ -3237,7 +3241,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
op := advance_token(p) op := advance_token(p)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
ac := ast.new(ast.Auto_Cast, op.pos, expr.end) ac := ast.new(ast.Auto_Cast, op.pos, expr)
ac.op = op ac.op = op
ac.expr = expr ac.expr = expr
return ac return ac
@@ -3248,7 +3252,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
op := advance_token(p) op := advance_token(p)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
ue := ast.new(ast.Unary_Expr, op.pos, expr.end) ue := ast.new(ast.Unary_Expr, op.pos, expr)
ue.op = op ue.op = op
ue.expr = expr ue.expr = expr
return ue return ue
@@ -3258,7 +3262,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
error(p, op.pos, "unary '%s' operator is not supported", op.text) error(p, op.pos, "unary '%s' operator is not supported", op.text)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
ue := ast.new(ast.Unary_Expr, op.pos, expr.end) ue := ast.new(ast.Unary_Expr, op.pos, expr)
ue.op = op ue.op = op
ue.expr = expr ue.expr = expr
return ue return ue
@@ -3266,7 +3270,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Period: case .Period:
op := advance_token(p) op := advance_token(p)
field := parse_ident(p) field := parse_ident(p)
ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end) ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field)
ise.field = field ise.field = field
return ise return ise
@@ -3407,7 +3411,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
error(p, p.curr_tok.pos, "no right-hand side in assignment statement") error(p, p.curr_tok.pos, "no right-hand side in assignment statement")
return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok)) return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok))
} }
stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1].end) stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1])
stmt.lhs = lhs stmt.lhs = lhs
stmt.op = op stmt.op = op
stmt.rhs = rhs stmt.rhs = rhs
@@ -3424,7 +3428,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
rhs := make([]^ast.Expr, 1) rhs := make([]^ast.Expr, 1)
rhs[0] = expr rhs[0] = expr
stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1].end) stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1])
stmt.lhs = lhs stmt.lhs = lhs
stmt.op = op stmt.op = op
stmt.rhs = rhs stmt.rhs = rhs
@@ -3466,7 +3470,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
error(p, op.pos, "postfix '%s' statement is not supported", op.text) error(p, op.pos, "postfix '%s' statement is not supported", op.text)
} }
es := ast.new(ast.Expr_Stmt, lhs[0].pos, lhs[0].end) es := ast.new(ast.Expr_Stmt, lhs[0].pos, lhs[0])
es.expr = lhs[0] es.expr = lhs[0]
return es return es
} }
+1 -1
View File
@@ -287,7 +287,7 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
if size_of(E) > 0 && cap(array)-len(array) > 0 { if size_of(E) > 0 && cap(array)-len(array) > 0 {
ti := type_info_of(typeid_of(T)) ti := type_info_of(T)
ti = type_info_base(ti) ti = type_info_base(ti)
si := &ti.variant.(Type_Info_Struct) si := &ti.variant.(Type_Info_Struct)
field_count: uintptr field_count: uintptr
+1 -1
View File
@@ -44,7 +44,7 @@ _ :: intrinsics
MAP_LOAD_FACTOR :: 75 MAP_LOAD_FACTOR :: 75
// Minimum log2 capacity. // Minimum log2 capacity.
MAP_MIN_LOG2_CAPACITY :: 6 // 64 elements MAP_MIN_LOG2_CAPACITY :: 3 // 8 elements
// Has to be less than 100% though. // Has to be less than 100% though.
#assert(MAP_LOAD_FACTOR < 100) #assert(MAP_LOAD_FACTOR < 100)
+84 -35
View File
@@ -49,7 +49,7 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
``` ```
``` ```
small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0, small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0} 2, 0, 0, 0}
large_items := slice.reinterpret([]i64, small_items) large_items := slice.reinterpret([]i64, small_items)
assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes. assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
``` ```
@@ -117,46 +117,95 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
return -1, false return -1, false
} }
/*
Binary search searches the given slice for the given element.
If the slice is not sorted, the returned index is unspecified and meaningless.
If the value is found then the returned int is the index of the matching element.
If there are multiple matches, then any one of the matches could be returned.
If the value is not found then the returned int is the index where a matching
element could be inserted while maintaining sorted order.
# Examples
Looks up a series of four elements. The first is found, with a
uniquely determined position; the second and third are not
found; the fourth could match any position in `[1, 4]`.
```
index: int
found: bool
s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
index, found = slice.binary_search(s, 13)
assert(index == 9 && found == true)
index, found = slice.binary_search(s, 4)
assert(index == 7 && found == false)
index, found = slice.binary_search(s, 100)
assert(index == 13 && found == false)
index, found = slice.binary_search(s, 1)
assert(index >= 1 && index <= 4 && found == true)
```
For slices of more complex types see: binary_search_by
*/
@(require_results) @(require_results)
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
where intrinsics.type_is_ordered(T) #no_bounds_check { where intrinsics.type_is_ordered(T) #no_bounds_check
{
n := len(array) // I would like to use binary_search_by(array, key, cmp) here, but it doesn't like it:
switch n { // Cannot assign value 'cmp' of type 'proc($E, $E) -> Ordering' to 'proc(i32, i32) -> Ordering' in argument
case 0: return binary_search_by(array, key, proc(key: T, element: T) -> Ordering {
return -1, false
case 1:
if array[0] == key {
return 0, true
}
return -1, false
}
lo, hi := 0, n-1
for array[hi] != array[lo] && key >= array[lo] && key <= array[hi] {
when intrinsics.type_is_ordered_numeric(T) {
// NOTE(bill): This is technically interpolation search
m := lo + int((key - array[lo]) * T(hi - lo) / (array[hi] - array[lo]))
} else {
m := lo + (hi - lo)/2
}
switch { switch {
case array[m] < key: case element < key: return .Less
lo = m + 1 case element > key: return .Greater
case key < array[m]: case: return .Equal
hi = m - 1
case:
return m, true
} }
} })
if key == array[lo] {
return lo, true
}
return -1, false
} }
@(require_results)
binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> (index: int, found: bool)
where intrinsics.type_is_ordered(T) #no_bounds_check
{
// INVARIANTS:
// - 0 <= left <= (left + size = right) <= len(array)
// - f returns .Less for everything in array[:left]
// - f returns .Greater for everything in array[right:]
size := len(array)
left := 0
right := size
for left < right {
mid := left + size / 2
// Steps to verify this is in-bounds:
// 1. We note that `size` is strictly positive due to the loop condition
// 2. Therefore `size/2 < size`
// 3. Adding `left` to both sides yields `(left + size/2) < (left + size)`
// 4. We know from the invariant that `left + size <= len(array)`
// 5. Therefore `left + size/2 < self.len()`
cmp := f(key, array[mid])
left = mid + 1 if cmp == .Less else left
right = mid if cmp == .Greater else right
switch cmp {
case .Equal: return mid, true
case .Less: left = mid + 1
case .Greater: right = mid
}
size = right - left
}
return left, false
}
@(require_results) @(require_results)
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
+1 -1
View File
@@ -718,7 +718,7 @@ Perf_Event_Sample_Type_Bits :: enum {
} }
/// Describes field sets to include in mmaped page /// Describes field sets to include in mmaped page
Perf_Read_Format :: enum { Perf_Read_Format_Bits :: enum {
TOTAL_TIME_ENABLED = 0, TOTAL_TIME_ENABLED = 0,
TOTAL_TIME_RUNNING = 1, TOTAL_TIME_RUNNING = 1,
ID = 2, ID = 2,
+2
View File
@@ -283,6 +283,8 @@ Perf_Flags :: bit_set[Perf_Flags_Bits; uint]
Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64] Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64]
Perf_Read_Format :: distinct bit_set[Perf_Read_Format_Bits; u64]
Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64] Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64]
Perf_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64] Perf_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64]
+250
View File
@@ -0,0 +1,250 @@
// +build windows
package sys_windows
foreign import "system:Dbghelp.lib"
RVA :: DWORD
MINIDUMP_LOCATION_DESCRIPTOR :: struct {
DataSize: ULONG32,
Rva: RVA,
}
MINIDUMP_DIRECTORY :: struct {
StreamType: ULONG32,
Location: MINIDUMP_LOCATION_DESCRIPTOR,
}
MINIDUMP_EXCEPTION_INFORMATION :: struct {
ThreadId: DWORD,
ExceptionPointers: ^EXCEPTION_POINTERS,
ClientPointers: BOOL,
}
MINIDUMP_MEMORY_INFO :: struct {
BaseAddress: ULONG64,
AllocationBase: ULONG64,
AllocationProtect: ULONG32,
__alignment1: ULONG32,
RegionSize: ULONG64,
State: ULONG32,
Protect: ULONG32,
Type: ULONG32,
__alignment2: ULONG32,
}
MINIDUMP_USER_STREAM :: struct {
Type: ULONG32,
BufferSize: ULONG,
Buffer: PVOID,
}
MINIDUMP_USER_STREAM_INFORMATION :: struct {
UserStreamCount: ULONG,
UserStreamArray: ^MINIDUMP_USER_STREAM,
}
MINIDUMP_CALLBACK_ROUTINE :: #type proc "stdcall" (
CallbackParam: PVOID,
CallbackInput: ^MINIDUMP_CALLBACK_INPUT,
CallbackOutpu: ^MINIDUMP_CALLBACK_OUTPUT,
) -> BOOL
MINIDUMP_CALLBACK_INFORMATION :: struct {
CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE,
CallbackParam: PVOID,
}
MINIDUMP_CALLBACK_INPUT :: struct {
ProcessId: ULONG,
ProcessHandle: HANDLE,
CallbackType: ULONG,
using _: struct #raw_union {
Status: HRESULT,
Thread: MINIDUMP_THREAD_CALLBACK,
ThreadEx: MINIDUMP_THREAD_EX_CALLBACK,
Module: MINIDUMP_MODULE_CALLBACK,
IncludeThread: MINIDUMP_INCLUDE_THREAD_CALLBACK,
IncludeModule: MINIDUMP_INCLUDE_MODULE_CALLBACK,
Io: MINIDUMP_IO_CALLBACK,
ReadMemoryFailure: MINIDUMP_READ_MEMORY_FAILURE_CALLBACK,
SecondaryFlags: ULONG,
VmQuery: MINIDUMP_VM_QUERY_CALLBACK,
VmPreRead: MINIDUMP_VM_PRE_READ_CALLBACK,
VmPostRead: MINIDUMP_VM_POST_READ_CALLBACK,
},
}
_MINIDUMP_ARM64_PAD :: ULONG when ODIN_ARCH == .arm64 else struct {}
MINIDUMP_THREAD_CALLBACK :: struct {
ThreadId: ULONG,
ThreadHandle: HANDLE,
Pad: _MINIDUMP_ARM64_PAD,
Context: CONTEXT,
SizeOfContext: ULONG,
StackBase: ULONG64,
StackEnd: ULONG64,
}
MINIDUMP_THREAD_EX_CALLBACK :: struct {
ThreadId: ULONG,
ThreadHandle: HANDLE,
Pad: _MINIDUMP_ARM64_PAD,
Context: CONTEXT,
SizeOfContext: ULONG,
StackBase: ULONG64,
StackEnd: ULONG64,
BackingStoreBase: ULONG64,
BackingStoreEnd: ULONG64,
}
MINIDUMP_INCLUDE_THREAD_CALLBACK :: struct {
ThreadId: ULONG,
}
// NOTE(jakubtomsu): From verrsrc.h
VS_FIXEDFILEINFO :: struct {
dwSignature: DWORD, /* e.g. 0xfeef04bd */
dwStrucVersion: DWORD, /* e.g. 0x00000042 = "0.42" */
dwFileVersionMS: DWORD, /* e.g. 0x00030075 = "3.75" */
dwFileVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */
dwProductVersionMS: DWORD, /* e.g. 0x00030010 = "3.10" */
dwProductVersionLS: DWORD, /* e.g. 0x00000031 = "0.31" */
dwFileFlagsMask: DWORD, /* = 0x3F for version "0.42" */
dwFileFlags: DWORD, /* e.g. VFF_DEBUG | VFF_PRERELEASE */
dwFileOS: DWORD, /* e.g. VOS_DOS_WINDOWS16 */
dwFileType: DWORD, /* e.g. VFT_DRIVER */
dwFileSubtype: DWORD, /* e.g. VFT2_DRV_KEYBOARD */
dwFileDateMS: DWORD, /* e.g. 0 */
dwFileDateLS: DWORD, /* e.g. 0 */
}
MINIDUMP_MODULE_CALLBACK :: struct {
FullPath: ^WCHAR,
BaseOfImage: ULONG64,
SizeOfImage: ULONG,
CheckSum: ULONG,
TimeDateStamp: ULONG,
VersionInfo: VS_FIXEDFILEINFO,
CvRecord: PVOID,
SizeOfCvRecord: ULONG,
MiscRecord: PVOID,
SizeOfMiscRecord: ULONG,
}
MINIDUMP_INCLUDE_MODULE_CALLBACK :: struct {
BaseOfImage: u64,
}
MINIDUMP_IO_CALLBACK :: struct {
Handle: HANDLE,
Offset: ULONG64,
Buffer: PVOID,
BufferBytes: ULONG,
}
MINIDUMP_READ_MEMORY_FAILURE_CALLBACK :: struct {
Offset: ULONG64,
Bytes: ULONG,
FailureStatus: HRESULT,
}
MINIDUMP_VM_QUERY_CALLBACK :: struct {
Offset: ULONG64,
}
MINIDUMP_VM_PRE_READ_CALLBACK :: struct {
Offset: ULONG64,
Buffer: PVOID,
Size: ULONG,
}
MINIDUMP_VM_POST_READ_CALLBACK :: struct {
Offset: ULONG64,
Buffer: PVOID,
Size: ULONG,
Completed: ULONG,
Status: HRESULT,
}
MINIDUMP_CALLBACK_OUTPUT :: struct {
using _: struct #raw_union {
ModuleWriteFlags: ULONG,
ThreadWriteFlags: ULONG,
SecondaryFlags: ULONG,
using _: struct {
MemoryBase: ULONG64,
MemorySize: ULONG,
},
using _: struct {
CheckCancel: BOOL,
Cancel: BOOL,
},
Handle: HANDLE,
using _: struct {
VmRegion: MINIDUMP_MEMORY_INFO,
Continue: BOOL,
},
using _: struct {
VmQueryStatus: HRESULT,
VmQueryResult: MINIDUMP_MEMORY_INFO,
},
using _: struct {
VmReadStatus: HRESULT,
VmReadBytesCompleted: ULONG,
},
Status: HRESULT,
},
}
MINIDUMP_TYPE :: enum u32 {
Normal = 0x00000000,
WithDataSegs = 0x00000001,
WithFullMemory = 0x00000002,
WithHandleData = 0x00000004,
FilterMemory = 0x00000008,
ScanMemory = 0x00000010,
WithUnloadedModules = 0x00000020,
WithIndirectlyReferencedMemory = 0x00000040,
FilterModulePaths = 0x00000080,
WithProcessThreadData = 0x00000100,
WithPrivateReadWriteMemory = 0x00000200,
WithoutOptionalData = 0x00000400,
WithFullMemoryInfo = 0x00000800,
WithThreadInfo = 0x00001000,
WithCodeSegs = 0x00002000,
WithoutAuxiliaryState = 0x00004000,
WithFullAuxiliaryState = 0x00008000,
WithPrivateWriteCopyMemory = 0x00010000,
IgnoreInaccessibleMemory = 0x00020000,
WithTokenInformation = 0x00040000,
WithModuleHeaders = 0x00080000,
FilterTriage = 0x00100000,
WithAvxXStateContext = 0x00200000,
WithIptTrace = 0x00400000,
ScanInaccessiblePartialPages = 0x00800000,
FilterWriteCombinedMemory = 0x01000000,
ValidTypeFlags = 0x01ffffff,
}
@(default_calling_convention = "stdcall")
foreign Dbghelp {
MiniDumpWriteDump :: proc(
hProcess: HANDLE,
ProcessId: DWORD,
hFile: HANDLE,
DumpType: MINIDUMP_TYPE,
ExceptionParam: ^MINIDUMP_EXCEPTION_INFORMATION,
UserStreamParam: ^MINIDUMP_USER_STREAM_INFORMATION,
CallbackPara: ^MINIDUMP_CALLBACK_INFORMATION,
) -> BOOL ---
MiniDumpReadDumpStream :: proc(
BaseOfDump: PVOID,
StreamNumber: ULONG,
Dir: ^^MINIDUMP_DIRECTORY,
StreamPointer: ^PVOID,
StreamSize: ^ULONG,
) -> BOOL ---
}
+1
View File
@@ -43,5 +43,6 @@ foreign dwmapi {
DwmFlush :: proc() -> HRESULT --- DwmFlush :: proc() -> HRESULT ---
DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT --- DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT ---
DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT --- DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT ---
DwmGetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: PVOID, cbAttribute: DWORD) -> HRESULT ---
DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT --- DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT ---
} }
+7
View File
@@ -10,6 +10,8 @@ foreign gdi32 {
DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- DeleteObject :: proc(ho: HGDIOBJ) -> BOOL ---
SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
CreateCompatibleDC :: proc(hdc: HDC) -> HDC ---
CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH ---
CreateDIBitmap :: proc( CreateDIBitmap :: proc(
@@ -81,6 +83,11 @@ foreign gdi32 {
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL --- GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH --- CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH ---
GetObjectW :: proc(h: HANDLE, c: c_int, pv: LPVOID) -> int ---
CreateCompatibleBitmap :: proc(hdc: HDC, cx, cy: c_int) -> HBITMAP ---
BitBlt :: proc(hdc: HDC, x, y, cx, cy: c_int, hdcSrc: HDC, x1, y1: c_int, rop: DWORD) -> BOOL ---
GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> int ---
} }
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
+20 -1
View File
@@ -172,6 +172,7 @@ foreign kernel32 {
TolerableDelay: ULONG, TolerableDelay: ULONG,
) -> BOOL --- ) -> BOOL ---
WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD --- WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD ---
WaitForSingleObjectEx :: proc(hHandle: HANDLE, dwMilliseconds: DWORD, bAlterable: BOOL) -> DWORD ---
Sleep :: proc(dwMilliseconds: DWORD) --- Sleep :: proc(dwMilliseconds: DWORD) ---
GetProcessId :: proc(handle: HANDLE) -> DWORD --- GetProcessId :: proc(handle: HANDLE) -> DWORD ---
CopyFileW :: proc( CopyFileW :: proc(
@@ -290,6 +291,14 @@ foreign kernel32 {
hTemplateFile: HANDLE, hTemplateFile: HANDLE,
) -> HANDLE --- ) -> HANDLE ---
GetFileTime :: proc(
hFile: HANDLE,
lpCreationTime: LPFILETIME,
lpLastAccessTime: LPFILETIME,
lpLastWriteTime: LPFILETIME,
) -> BOOL ---
CompareFileTime :: proc(lpFileTime1: LPFILETIME, lpFileTime2: LPFILETIME) -> LONG ---
FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE --- FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE ---
FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL --- FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL ---
FindClose :: proc(findFile: HANDLE) -> BOOL --- FindClose :: proc(findFile: HANDLE) -> BOOL ---
@@ -320,6 +329,13 @@ foreign kernel32 {
bWaitAll: BOOL, bWaitAll: BOOL,
dwMilliseconds: DWORD, dwMilliseconds: DWORD,
) -> DWORD --- ) -> DWORD ---
WaitForMultipleObjectsEx :: proc(
nCount: DWORD,
lpHandles: ^HANDLE,
bWaitAll: BOOL,
dwMilliseconds: DWORD,
bAlterable: BOOL,
) -> DWORD ---
CreateNamedPipeW :: proc( CreateNamedPipeW :: proc(
lpName: LPCWSTR, lpName: LPCWSTR,
dwOpenMode: DWORD, dwOpenMode: DWORD,
@@ -346,6 +362,9 @@ foreign kernel32 {
LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
LocalFree :: proc(mem: LPVOID) -> LPVOID --- LocalFree :: proc(mem: LPVOID) -> LPVOID ---
GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID ---
GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
GlobalFree :: proc(mem: LPVOID) -> LPVOID ---
ReadDirectoryChangesW :: proc( ReadDirectoryChangesW :: proc(
hDirectory: HANDLE, hDirectory: HANDLE,
@@ -414,7 +433,7 @@ foreign kernel32 {
GetConsoleWindow :: proc() -> HWND --- GetConsoleWindow :: proc() -> HWND ---
GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL --- GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL ---
SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL --- SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL ---
SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute : BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL --- SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL ---
GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
+145
View File
@@ -0,0 +1,145 @@
// +build windows
package sys_windows
FOLDERID_NetworkFolder :: GUID {0xD20BEEC4, 0x5CA8, 0x4905, {0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53}}
FOLDERID_ComputerFolder :: GUID {0x0AC0837C, 0xBBF8, 0x452A, {0x85, 0x0D, 0x79, 0xD0, 0x8E, 0x66, 0x7C, 0xA7}}
FOLDERID_InternetFolder :: GUID {0x4D9F7874, 0x4E0C, 0x4904, {0x96, 0x7B, 0x40, 0xB0, 0xD2, 0x0C, 0x3E, 0x4B}}
FOLDERID_ControlPanelFolder :: GUID {0x82A74AEB, 0xAEB4, 0x465C, {0xA0, 0x14, 0xD0, 0x97, 0xEE, 0x34, 0x6D, 0x63}}
FOLDERID_PrintersFolder :: GUID {0x76FC4E2D, 0xD6AD, 0x4519, {0xA6, 0x63, 0x37, 0xBD, 0x56, 0x06, 0x81, 0x85}}
FOLDERID_SyncManagerFolder :: GUID {0x43668BF8, 0xC14E, 0x49B2, {0x97, 0xC9, 0x74, 0x77, 0x84, 0xD7, 0x84, 0xB7}}
FOLDERID_SyncSetupFolder :: GUID {0xf214138 , 0xb1d3, 0x4a90, {0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}}
FOLDERID_ConflictFolder :: GUID {0x4bfefb45, 0x347d, 0x4006, {0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}}
FOLDERID_SyncResultsFolder :: GUID {0x289a9a43, 0xbe44, 0x4057, {0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}}
FOLDERID_RecycleBinFolder :: GUID {0xB7534046, 0x3ECB, 0x4C18, {0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC}}
FOLDERID_ConnectionsFolder :: GUID {0x6F0CD92B, 0x2E97, 0x45D1, {0x88, 0xFF, 0xB0, 0xD1, 0x86, 0xB8, 0xDE, 0xDD}}
FOLDERID_Fonts :: GUID {0xFD228CB7, 0xAE11, 0x4AE3, {0x86, 0x4C, 0x16, 0xF3, 0x91, 0x0A, 0xB8, 0xFE}}
FOLDERID_Desktop :: GUID {0xB4BFCC3A, 0xDB2C, 0x424C, {0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41}}
FOLDERID_Startup :: GUID {0xB97D20BB, 0xF46A, 0x4C97, {0xBA, 0x10, 0x5E, 0x36, 0x08, 0x43, 0x08, 0x54}}
FOLDERID_Programs :: GUID {0xA77F5D77, 0x2E2B, 0x44C3, {0xA6, 0xA2, 0xAB, 0xA6, 0x01, 0x05, 0x4A, 0x51}}
FOLDERID_StartMenu :: GUID {0x625B53C3, 0xAB48, 0x4EC1, {0xBA, 0x1F, 0xA1, 0xEF, 0x41, 0x46, 0xFC, 0x19}}
FOLDERID_Recent :: GUID {0xAE50C081, 0xEBD2, 0x438A, {0x86, 0x55, 0x8A, 0x09, 0x2E, 0x34, 0x98, 0x7A}}
FOLDERID_SendTo :: GUID {0x8983036C, 0x27C0, 0x404B, {0x8F, 0x08, 0x10, 0x2D, 0x10, 0xDC, 0xFD, 0x74}}
FOLDERID_Documents :: GUID {0xFDD39AD0, 0x238F, 0x46AF, {0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7}}
FOLDERID_Favorites :: GUID {0x1777F761, 0x68AD, 0x4D8A, {0x87, 0xBD, 0x30, 0xB7, 0x59, 0xFA, 0x33, 0xDD}}
FOLDERID_NetHood :: GUID {0xC5ABBF53, 0xE17F, 0x4121, {0x89, 0x00, 0x86, 0x62, 0x6F, 0xC2, 0xC9, 0x73}}
FOLDERID_PrintHood :: GUID {0x9274BD8D, 0xCFD1, 0x41C3, {0xB3, 0x5E, 0xB1, 0x3F, 0x55, 0xA7, 0x58, 0xF4}}
FOLDERID_Templates :: GUID {0xA63293E8, 0x664E, 0x48DB, {0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7}}
FOLDERID_CommonStartup :: GUID {0x82A5EA35, 0xD9CD, 0x47C5, {0x96, 0x29, 0xE1, 0x5D, 0x2F, 0x71, 0x4E, 0x6E}}
FOLDERID_CommonPrograms :: GUID {0x0139D44E, 0x6AFE, 0x49F2, {0x86, 0x90, 0x3D, 0xAF, 0xCA, 0xE6, 0xFF, 0xB8}}
FOLDERID_CommonStartMenu :: GUID {0xA4115719, 0xD62E, 0x491D, {0xAA, 0x7C, 0xE7, 0x4B, 0x8B, 0xE3, 0xB0, 0x67}}
FOLDERID_PublicDesktop :: GUID {0xC4AA340D, 0xF20F, 0x4863, {0xAF, 0xEF, 0xF8, 0x7E, 0xF2, 0xE6, 0xBA, 0x25}}
FOLDERID_ProgramData :: GUID {0x62AB5D82, 0xFDC1, 0x4DC3, {0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97}}
FOLDERID_CommonTemplates :: GUID {0xB94237E7, 0x57AC, 0x4347, {0x91, 0x51, 0xB0, 0x8C, 0x6C, 0x32, 0xD1, 0xF7}}
FOLDERID_PublicDocuments :: GUID {0xED4824AF, 0xDCE4, 0x45A8, {0x81, 0xE2, 0xFC, 0x79, 0x65, 0x08, 0x36, 0x34}}
FOLDERID_RoamingAppData :: GUID {0x3EB685DB, 0x65F9, 0x4CF6, {0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D}}
FOLDERID_LocalAppData :: GUID {0xF1B32785, 0x6FBA, 0x4FCF, {0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91}}
FOLDERID_LocalAppDataLow :: GUID {0xA520A1A4, 0x1780, 0x4FF6, {0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16}}
FOLDERID_InternetCache :: GUID {0x352481E8, 0x33BE, 0x4251, {0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D}}
FOLDERID_Cookies :: GUID {0x2B0F765D, 0xC0E9, 0x4171, {0x90, 0x8E, 0x08, 0xA6, 0x11, 0xB8, 0x4F, 0xF6}}
FOLDERID_History :: GUID {0xD9DC8A3B, 0xB784, 0x432E, {0xA7, 0x81, 0x5A, 0x11, 0x30, 0xA7, 0x59, 0x63}}
FOLDERID_System :: GUID {0x1AC14E77, 0x02E7, 0x4E5D, {0xB7, 0x44, 0x2E, 0xB1, 0xAE, 0x51, 0x98, 0xB7}}
FOLDERID_SystemX86 :: GUID {0xD65231B0, 0xB2F1, 0x4857, {0xA4, 0xCE, 0xA8, 0xE7, 0xC6, 0xEA, 0x7D, 0x27}}
FOLDERID_Windows :: GUID {0xF38BF404, 0x1D43, 0x42F2, {0x93, 0x05, 0x67, 0xDE, 0x0B, 0x28, 0xFC, 0x23}}
FOLDERID_Profile :: GUID {0x5E6C858F, 0x0E22, 0x4760, {0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73}}
FOLDERID_Pictures :: GUID {0x33E28130, 0x4E1E, 0x4676, {0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB}}
FOLDERID_ProgramFilesX86 :: GUID {0x7C5A40EF, 0xA0FB, 0x4BFC, {0x87, 0x4A, 0xC0, 0xF2, 0xE0, 0xB9, 0xFA, 0x8E}}
FOLDERID_ProgramFilesCommonX86 :: GUID {0xDE974D24, 0xD9C6, 0x4D3E, {0xBF, 0x91, 0xF4, 0x45, 0x51, 0x20, 0xB9, 0x17}}
FOLDERID_ProgramFilesX64 :: GUID {0x6d809377, 0x6af0, 0x444b, {0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}}
FOLDERID_ProgramFilesCommonX64 :: GUID {0x6365d5a7, 0xf0d , 0x45e5, {0x87, 0xf6, 0xd, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d }}
FOLDERID_ProgramFiles :: GUID {0x905e63b6, 0xc1bf, 0x494e, {0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}}
FOLDERID_ProgramFilesCommon :: GUID {0xF7F1ED05, 0x9F6D, 0x47A2, {0xAA, 0xAE, 0x29, 0xD3, 0x17, 0xC6, 0xF0, 0x66}}
FOLDERID_UserProgramFiles :: GUID {0x5cd7aee2, 0x2219, 0x4a67, {0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}}
FOLDERID_UserProgramFilesCommon :: GUID {0xbcbd3057, 0xca5c, 0x4622, {0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}}
FOLDERID_AdminTools :: GUID {0x724EF170, 0xA42D, 0x4FEF, {0x9F, 0x26, 0xB6, 0x0E, 0x84, 0x6F, 0xBA, 0x4F}}
FOLDERID_CommonAdminTools :: GUID {0xD0384E7D, 0xBAC3, 0x4797, {0x8F, 0x14, 0xCB, 0xA2, 0x29, 0xB3, 0x92, 0xB5}}
FOLDERID_Music :: GUID {0x4BD8D571, 0x6D19, 0x48D3, {0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43}}
FOLDERID_Videos :: GUID {0x18989B1D, 0x99B5, 0x455B, {0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC}}
FOLDERID_Ringtones :: GUID {0xC870044B, 0xF49E, 0x4126, {0xA9, 0xC3, 0xB5, 0x2A, 0x1F, 0xF4, 0x11, 0xE8}}
FOLDERID_PublicPictures :: GUID {0xB6EBFB86, 0x6907, 0x413C, {0x9A, 0xF7, 0x4F, 0xC2, 0xAB, 0xF0, 0x7C, 0xC5}}
FOLDERID_PublicMusic :: GUID {0x3214FAB5, 0x9757, 0x4298, {0xBB, 0x61, 0x92, 0xA9, 0xDE, 0xAA, 0x44, 0xFF}}
FOLDERID_PublicVideos :: GUID {0x2400183A, 0x6185, 0x49FB, {0xA2, 0xD8, 0x4A, 0x39, 0x2A, 0x60, 0x2B, 0xA3}}
FOLDERID_PublicRingtones :: GUID {0xE555AB60, 0x153B, 0x4D17, {0x9F, 0x04, 0xA5, 0xFE, 0x99, 0xFC, 0x15, 0xEC}}
FOLDERID_ResourceDir :: GUID {0x8AD10C31, 0x2ADB, 0x4296, {0xA8, 0xF7, 0xE4, 0x70, 0x12, 0x32, 0xC9, 0x72}}
FOLDERID_LocalizedResourcesDir :: GUID {0x2A00375E, 0x224C, 0x49DE, {0xB8, 0xD1, 0x44, 0x0D, 0xF7, 0xEF, 0x3D, 0xDC}}
FOLDERID_CommonOEMLinks :: GUID {0xC1BAE2D0, 0x10DF, 0x4334, {0xBE, 0xDD, 0x7A, 0xA2, 0x0B, 0x22, 0x7A, 0x9D}}
FOLDERID_CDBurning :: GUID {0x9E52AB10, 0xF80D, 0x49DF, {0xAC, 0xB8, 0x43, 0x30, 0xF5, 0x68, 0x78, 0x55}}
FOLDERID_UserProfiles :: GUID {0x0762D272, 0xC50A, 0x4BB0, {0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80}}
FOLDERID_Playlists :: GUID {0xDE92C1C7, 0x837F, 0x4F69, {0xA3, 0xBB, 0x86, 0xE6, 0x31, 0x20, 0x4A, 0x23}}
FOLDERID_SamplePlaylists :: GUID {0x15CA69B3, 0x30EE, 0x49C1, {0xAC, 0xE1, 0x6B, 0x5E, 0xC3, 0x72, 0xAF, 0xB5}}
FOLDERID_SampleMusic :: GUID {0xB250C668, 0xF57D, 0x4EE1, {0xA6, 0x3C, 0x29, 0x0E, 0xE7, 0xD1, 0xAA, 0x1F}}
FOLDERID_SamplePictures :: GUID {0xC4900540, 0x2379, 0x4C75, {0x84, 0x4B, 0x64, 0xE6, 0xFA, 0xF8, 0x71, 0x6B}}
FOLDERID_SampleVideos :: GUID {0x859EAD94, 0x2E85, 0x48AD, {0xA7, 0x1A, 0x09, 0x69, 0xCB, 0x56, 0xA6, 0xCD}}
FOLDERID_PhotoAlbums :: GUID {0x69D2CF90, 0xFC33, 0x4FB7, {0x9A, 0x0C, 0xEB, 0xB0, 0xF0, 0xFC, 0xB4, 0x3C}}
FOLDERID_Public :: GUID {0xDFDF76A2, 0xC82A, 0x4D63, {0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85}}
FOLDERID_ChangeRemovePrograms :: GUID {0xdf7266ac, 0x9274, 0x4867, {0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}}
FOLDERID_AppUpdates :: GUID {0xa305ce99, 0xf527, 0x492b, {0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}}
FOLDERID_AddNewPrograms :: GUID {0xde61d971, 0x5ebc, 0x4f02, {0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}}
FOLDERID_Downloads :: GUID {0x374de290, 0x123f, 0x4565, {0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}}
FOLDERID_PublicDownloads :: GUID {0x3d644c9b, 0x1fb8, 0x4f30, {0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}}
FOLDERID_SavedSearches :: GUID {0x7d1d3a04, 0xdebb, 0x4115, {0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}}
FOLDERID_QuickLaunch :: GUID {0x52a4f021, 0x7b75, 0x48a9, {0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}}
FOLDERID_Contacts :: GUID {0x56784854, 0xc6cb, 0x462b, {0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}}
FOLDERID_SidebarParts :: GUID {0xa75d362e, 0x50fc, 0x4fb7, {0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}}
FOLDERID_SidebarDefaultParts :: GUID {0x7b396e54, 0x9ec5, 0x4300, {0xbe, 0xa , 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}}
FOLDERID_PublicGameTasks :: GUID {0xdebf2536, 0xe1a8, 0x4c59, {0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}}
FOLDERID_GameTasks :: GUID {0x54fae61 , 0x4dd8, 0x4787, {0x80, 0xb6, 0x9 , 0x2 , 0x20, 0xc4, 0xb7, 0x0 }}
FOLDERID_SavedGames :: GUID {0x4c5c32ff, 0xbb9d, 0x43b0, {0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}}
FOLDERID_Games :: GUID {0xcac52c1a, 0xb53d, 0x4edc, {0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}}
FOLDERID_SEARCH_MAPI :: GUID {0x98ec0e18, 0x2098, 0x4d44, {0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}}
FOLDERID_SEARCH_CSC :: GUID {0xee32e446, 0x31ca, 0x4aba, {0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}}
FOLDERID_Links :: GUID {0xbfb9d5e0, 0xc6a9, 0x404c, {0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}}
FOLDERID_UsersFiles :: GUID {0xf3ce0f7c, 0x4901, 0x4acc, {0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}}
FOLDERID_UsersLibraries :: GUID {0xa302545d, 0xdeff, 0x464b, {0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}}
FOLDERID_SearchHome :: GUID {0x190337d1, 0xb8ca, 0x4121, {0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}}
FOLDERID_OriginalImages :: GUID {0x2C36C0AA, 0x5812, 0x4b87, {0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}}
FOLDERID_DocumentsLibrary :: GUID {0x7b0db17d, 0x9cd2, 0x4a93, {0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}}
FOLDERID_MusicLibrary :: GUID {0x2112ab0a, 0xc86a, 0x4ffe, {0xa3, 0x68, 0xd , 0xe9, 0x6e, 0x47, 0x1 , 0x2e}}
FOLDERID_PicturesLibrary :: GUID {0xa990ae9f, 0xa03b, 0x4e80, {0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x4 }}
FOLDERID_VideosLibrary :: GUID {0x491e922f, 0x5643, 0x4af4, {0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}}
FOLDERID_RecordedTVLibrary :: GUID {0x1a6fdba2, 0xf42d, 0x4358, {0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}}
FOLDERID_HomeGroup :: GUID {0x52528a6b, 0xb9e3, 0x4add, {0xb6, 0xd , 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}}
FOLDERID_HomeGroupCurrentUser :: GUID {0x9b74b6a3, 0xdfd , 0x4f11, {0x9e, 0x78, 0x5f, 0x78, 0x0 , 0xf2, 0xe7, 0x72}}
FOLDERID_DeviceMetadataStore :: GUID {0x5ce4a5e9, 0xe4eb, 0x479d, {0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}}
FOLDERID_Libraries :: GUID {0x1b3ea5dc, 0xb587, 0x4786, {0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}}
FOLDERID_PublicLibraries :: GUID {0x48daf80b, 0xe6cf, 0x4f4e, {0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}}
FOLDERID_UserPinned :: GUID {0x9e3995ab, 0x1f9c, 0x4f13, {0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}}
FOLDERID_ImplicitAppShortcuts :: GUID {0xbcb5256f, 0x79f6, 0x4cee, {0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x2 , 0xfd, 0x46}}
FOLDERID_AccountPictures :: GUID {0x008ca0b1, 0x55b4, 0x4c56, {0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}}
FOLDERID_PublicUserTiles :: GUID {0x0482af6c, 0x08f1, 0x4c34, {0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}}
FOLDERID_AppsFolder :: GUID {0x1e87508d, 0x89c2, 0x42f0, {0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}}
FOLDERID_StartMenuAllPrograms :: GUID {0xf26305ef, 0x6948, 0x40b9, {0xb2, 0x55, 0x81, 0x45, 0x3d, 0x9 , 0xc7, 0x85}}
FOLDERID_CommonStartMenuPlaces :: GUID {0xa440879f, 0x87a0, 0x4f7d, {0xb7, 0x0 , 0x2 , 0x7 , 0xb9, 0x66, 0x19, 0x4a}}
FOLDERID_ApplicationShortcuts :: GUID {0xa3918781, 0xe5f2, 0x4890, {0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}}
FOLDERID_RoamingTiles :: GUID {0xbcfc5a , 0xed94, 0x4e48, {0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}}
FOLDERID_RoamedTileImages :: GUID {0xaaa8d5a5, 0xf1d6, 0x4259, {0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}}
FOLDERID_Screenshots :: GUID {0xb7bede81, 0xdf94, 0x4682, {0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}}
FOLDERID_CameraRoll :: GUID {0xab5fb87b, 0x7ce2, 0x4f83, {0x91, 0x5d, 0x55, 0x8 , 0x46, 0xc9, 0x53, 0x7b}}
FOLDERID_SkyDrive :: GUID {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
FOLDERID_OneDrive :: GUID {0xa52bba46, 0xe9e1, 0x435f, {0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
FOLDERID_SkyDriveDocuments :: GUID {0x24d89e24, 0x2f19, 0x4534, {0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}}
FOLDERID_SkyDrivePictures :: GUID {0x339719b5, 0x8c47, 0x4894, {0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}}
FOLDERID_SkyDriveMusic :: GUID {0xc3f2459e, 0x80d6, 0x45dc, {0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}}
FOLDERID_SkyDriveCameraRoll :: GUID {0x767e6811, 0x49cb, 0x4273, {0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}}
FOLDERID_SearchHistory :: GUID {0x0d4c3db6, 0x03a3, 0x462f, {0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}}
FOLDERID_SearchTemplates :: GUID {0x7e636bfe, 0xdfa9, 0x4d5e, {0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}}
FOLDERID_CameraRollLibrary :: GUID {0x2b20df75, 0x1eda, 0x4039, {0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}}
FOLDERID_SavedPictures :: GUID {0x3b193882, 0xd3ad, 0x4eab, {0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}}
FOLDERID_SavedPicturesLibrary :: GUID {0xe25b5812, 0xbe88, 0x4bd9, {0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}}
FOLDERID_RetailDemo :: GUID {0x12d4c69e, 0x24ad, 0x4923, {0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}}
FOLDERID_Device :: GUID {0x1C2AC1DC, 0x4358, 0x4B6C, {0x97, 0x33, 0xAF, 0x21, 0x15, 0x65, 0x76, 0xF0}}
FOLDERID_DevelopmentFiles :: GUID {0xdbe8e08e, 0x3053, 0x4bbc, {0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}}
FOLDERID_Objects3D :: GUID {0x31c0dd25, 0x9439, 0x4f12, {0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}}
FOLDERID_AppCaptures :: GUID {0xedc0fe71, 0x98d8, 0x4f4a, {0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}}
FOLDERID_LocalDocuments :: GUID {0xf42ee2d3, 0x909f, 0x4907, {0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}}
FOLDERID_LocalPictures :: GUID {0x0ddd015d, 0xb06c, 0x45d5, {0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}}
FOLDERID_LocalVideos :: GUID {0x35286a68, 0x3c57, 0x41a1, {0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}}
FOLDERID_LocalMusic :: GUID {0xa0c69a99, 0x21c8, 0x4671, {0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}}
FOLDERID_LocalDownloads :: GUID {0x7d83ee9b, 0x2244, 0x4e70, {0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}}
FOLDERID_RecordedCalls :: GUID {0x2f8b40c2, 0x83ed, 0x48ee, {0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}}
FOLDERID_AllAppMods :: GUID {0x7ad67899, 0x66af, 0x43ba, {0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}}
FOLDERID_CurrentAppMods :: GUID {0x3db40b20, 0x2a30, 0x4dbe, {0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}}
FOLDERID_AppDataDesktop :: GUID {0xb2c5e279, 0x7add, 0x439f, {0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}}
FOLDERID_AppDataDocuments :: GUID {0x7be16610, 0x1f7f, 0x44ac, {0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}}
FOLDERID_AppDataFavorites :: GUID {0x7cfbefbc, 0xde1f, 0x45aa, {0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}}
FOLDERID_AppDataProgramData :: GUID {0x559d40a3, 0xa036, 0x40fa, {0xaf, 0x61, 0x84, 0xcb, 0x43, 0xa , 0x4d, 0x34}}
FOLDERID_LocalStorage :: GUID {0xB3EB08D3, 0xA1F3, 0x496B, {0x86, 0x5A, 0x42, 0xB5, 0x36, 0xCD, 0xA0, 0xEC}}
+33
View File
@@ -25,6 +25,10 @@ foreign shell32 {
SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR --- SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR ---
Shell_NotifyIconW :: proc(dwMessage: DWORD, lpData: ^NOTIFYICONDATAW) -> BOOL --- Shell_NotifyIconW :: proc(dwMessage: DWORD, lpData: ^NOTIFYICONDATAW) -> BOOL ---
SHGetKnownFolderIDList :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppidl: rawptr) -> HRESULT ---
SHSetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, pszPath: PCWSTR ) -> HRESULT ---
SHGetKnownFolderPath :: proc(rfid: REFKNOWNFOLDERID, dwFlags: /* KNOWN_FOLDER_FLAG */ DWORD, hToken: HANDLE, ppszPath: ^LPWSTR) -> HRESULT ---
} }
APPBARDATA :: struct { APPBARDATA :: struct {
@@ -58,3 +62,32 @@ ABE_LEFT :: 0
ABE_TOP :: 1 ABE_TOP :: 1
ABE_RIGHT :: 2 ABE_RIGHT :: 2
ABE_BOTTOM :: 3 ABE_BOTTOM :: 3
KNOWNFOLDERID :: GUID
REFKNOWNFOLDERID :: ^KNOWNFOLDERID
KNOWN_FOLDER_FLAG :: enum u32 {
DEFAULT = 0x00000000,
// if NTDDI_VERSION >= NTDDI_WIN10_RS3
FORCE_APP_DATA_REDIRECTION = 0x00080000,
// if NTDDI_VERSION >= NTDDI_WIN10_RS2
RETURN_FILTER_REDIRECTION_TARGET = 0x00040000,
FORCE_PACKAGE_REDIRECTION = 0x00020000,
NO_PACKAGE_REDIRECTION = 0x00010000,
FORCE_APPCONTAINER_REDIRECTION = 0x00020000,
// if NTDDI_VERSION >= NTDDI_WIN7
NO_APPCONTAINER_REDIRECTION = 0x00010000,
CREATE = 0x00008000,
DONT_VERIFY = 0x00004000,
DONT_UNEXPAND = 0x00002000,
NO_ALIAS = 0x00001000,
INIT = 0x00000800,
DEFAULT_PATH = 0x00000400,
NOT_PARENT_RELATIVE = 0x00000200,
SIMPLE_IDLIST = 0x00000100,
ALIAS_ONLY = 0x80000000,
}
+12
View File
@@ -86,6 +86,8 @@ INT16 :: i16
INT32 :: i32 INT32 :: i32
INT64 :: i64 INT64 :: i64
ULONG32 :: u32
LONG32 :: i32
ULONG64 :: u64 ULONG64 :: u64
LONG64 :: i64 LONG64 :: i64
@@ -1969,6 +1971,16 @@ BITMAPINFO :: struct {
bmiColors: [1]RGBQUAD, bmiColors: [1]RGBQUAD,
} }
BITMAP :: struct {
bmType: LONG,
bmWidth: LONG,
bmHeight: LONG,
bmWidthBytes: LONG,
bmPlanes: WORD,
bmBitsPixel: WORD,
bmBits: LPVOID,
}
// pixel types // pixel types
PFD_TYPE_RGBA :: 0 PFD_TYPE_RGBA :: 0
PFD_TYPE_COLORINDEX :: 1 PFD_TYPE_COLORINDEX :: 1
+4
View File
@@ -136,6 +136,7 @@ foreign user32 {
GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL --- GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL ---
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT --- MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
ToUnicode :: proc(nVirtKey: UINT, wScanCode: UINT, lpKeyState: ^BYTE, pwszBuff: LPWSTR, cchBuff: c_int, wFlags: UINT) -> c_int ---
SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK --- SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK ---
UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL --- UnhookWindowsHookEx :: proc(hhk: HHOOK) -> BOOL ---
@@ -161,6 +162,8 @@ foreign user32 {
MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR --- MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR ---
EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL --- EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL ---
EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL ---
SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT ---
GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT ---
GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT --- GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT ---
@@ -310,6 +313,7 @@ Monitor_From_Flags :: enum DWORD {
} }
Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL
Window_Enum_Proc :: #type proc "stdcall" (HWND, LPARAM) -> BOOL
USER_DEFAULT_SCREEN_DPI :: 96 USER_DEFAULT_SCREEN_DPI :: 96
DPI_AWARENESS_CONTEXT :: distinct HANDLE DPI_AWARENESS_CONTEXT :: distinct HANDLE
+75 -29
View File
@@ -63,7 +63,9 @@ Translation :: enum u32 {
Soft_Line_End, Soft_Line_End,
} }
// init the state to some timeout and set the respective allocators
// - undo_state_allocator dictates the dynamic undo|redo arrays allocators
// - undo_text_allocator is the allocator which allocates strings only
init :: proc(s: ^State, undo_text_allocator, undo_state_allocator: runtime.Allocator, undo_timeout := DEFAULT_UNDO_TIMEOUT) { init :: proc(s: ^State, undo_text_allocator, undo_state_allocator: runtime.Allocator, undo_timeout := DEFAULT_UNDO_TIMEOUT) {
s.undo_timeout = undo_timeout s.undo_timeout = undo_timeout
@@ -74,6 +76,7 @@ init :: proc(s: ^State, undo_text_allocator, undo_state_allocator: runtime.Alloc
s.redo.allocator = undo_state_allocator s.redo.allocator = undo_state_allocator
} }
// clear undo|redo strings and delete their stacks
destroy :: proc(s: ^State) { destroy :: proc(s: ^State) {
undo_clear(s, &s.undo) undo_clear(s, &s.undo)
undo_clear(s, &s.redo) undo_clear(s, &s.redo)
@@ -82,7 +85,6 @@ destroy :: proc(s: ^State) {
s.builder = nil s.builder = nil
} }
// Call at the beginning of each frame // Call at the beginning of each frame
begin :: proc(s: ^State, id: u64, builder: ^strings.Builder) { begin :: proc(s: ^State, id: u64, builder: ^strings.Builder) {
assert(builder != nil) assert(builder != nil)
@@ -92,11 +94,7 @@ begin :: proc(s: ^State, id: u64, builder: ^strings.Builder) {
s.id = id s.id = id
s.selection = {len(builder.buf), 0} s.selection = {len(builder.buf), 0}
s.builder = builder s.builder = builder
s.current_time = time.tick_now() update_time(s)
if s.undo_timeout <= 0 {
s.undo_timeout = DEFAULT_UNDO_TIMEOUT
}
set_text(s, string(s.builder.buf[:]))
undo_clear(s, &s.undo) undo_clear(s, &s.undo)
undo_clear(s, &s.redo) undo_clear(s, &s.redo)
} }
@@ -107,12 +105,37 @@ end :: proc(s: ^State) {
s.builder = nil s.builder = nil
} }
set_text :: proc(s: ^State, text: string) { // update current time so "insert" can check for timeouts
strings.builder_reset(s.builder) update_time :: proc(s: ^State) {
strings.write_string(s.builder, text) s.current_time = time.tick_now()
if s.undo_timeout <= 0 {
s.undo_timeout = DEFAULT_UNDO_TIMEOUT
}
} }
// setup the builder, selection and undo|redo state once allowing to retain selection
setup_once :: proc(s: ^State, builder: ^strings.Builder) {
s.builder = builder
s.selection = { len(builder.buf), 0 }
undo_clear(s, &s.undo)
undo_clear(s, &s.redo)
}
// returns true when the builder had content to be cleared
// clear builder&selection and the undo|redo stacks
clear_all :: proc(s: ^State) -> (cleared: bool) {
if s.builder != nil && len(s.builder.buf) > 0 {
clear(&s.builder.buf)
s.selection = {}
cleared = true
}
undo_clear(s, &s.undo)
undo_clear(s, &s.redo)
return
}
// push current text state to the wanted undo|redo stack
undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error { undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error {
text := string(s.builder.buf[:]) text := string(s.builder.buf[:])
item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return) item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return)
@@ -125,18 +148,21 @@ undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator
return nil return nil
} }
// pop undo|redo state - push to redo|undo - set selection & text
undo :: proc(s: ^State, undo, redo: ^[dynamic]^Undo_State) { undo :: proc(s: ^State, undo, redo: ^[dynamic]^Undo_State) {
if len(undo) > 0 { if len(undo) > 0 {
undo_state_push(s, redo) undo_state_push(s, redo)
item := pop(undo) item := pop(undo)
s.selection = item.selection s.selection = item.selection
#no_bounds_check { #no_bounds_check {
set_text(s, string(item.text[:item.len])) strings.builder_reset(s.builder)
strings.write_string(s.builder, string(item.text[:item.len]))
} }
free(item, s.undo_text_allocator) free(item, s.undo_text_allocator)
} }
} }
// iteratively clearn the undo|redo stack and free each allocated text state
undo_clear :: proc(s: ^State, undo: ^[dynamic]^Undo_State) { undo_clear :: proc(s: ^State, undo: ^[dynamic]^Undo_State) {
for len(undo) > 0 { for len(undo) > 0 {
item := pop(undo) item := pop(undo)
@@ -144,6 +170,7 @@ undo_clear :: proc(s: ^State, undo: ^[dynamic]^Undo_State) {
} }
} }
// clear redo stack and check if the undo timeout gets hit
undo_check :: proc(s: ^State) { undo_check :: proc(s: ^State) {
undo_clear(s, &s.redo) undo_clear(s, &s.redo)
if time.tick_diff(s.last_edit_time, s.current_time) > s.undo_timeout { if time.tick_diff(s.last_edit_time, s.current_time) > s.undo_timeout {
@@ -152,8 +179,7 @@ undo_check :: proc(s: ^State) {
s.last_edit_time = s.current_time s.last_edit_time = s.current_time
} }
// insert text into the edit state - deletes the current selection
input_text :: proc(s: ^State, text: string) { input_text :: proc(s: ^State, text: string) {
if len(text) == 0 { if len(text) == 0 {
return return
@@ -166,6 +192,7 @@ input_text :: proc(s: ^State, text: string) {
s.selection = {offset, offset} s.selection = {offset, offset}
} }
// insert slice of runes into the edit state - deletes the current selection
input_runes :: proc(s: ^State, text: []rune) { input_runes :: proc(s: ^State, text: []rune) {
if len(text) == 0 { if len(text) == 0 {
return return
@@ -182,43 +209,55 @@ input_runes :: proc(s: ^State, text: []rune) {
s.selection = {offset, offset} s.selection = {offset, offset}
} }
// insert a single rune into the edit state - deletes the current selection
input_rune :: proc(s: ^State, r: rune) {
if has_selection(s) {
selection_delete(s)
}
offset := s.selection[0]
b, w := utf8.encode_rune(r)
insert(s, offset, string(b[:w]))
offset += w
s.selection = {offset, offset}
}
// insert a single rune into the edit state - deletes the current selection
insert :: proc(s: ^State, at: int, text: string) { insert :: proc(s: ^State, at: int, text: string) {
undo_check(s) undo_check(s)
inject_at(&s.builder.buf, at, text) inject_at(&s.builder.buf, at, text)
} }
// remove the wanted range withing, usually the selection within byte indices
remove :: proc(s: ^State, lo, hi: int) { remove :: proc(s: ^State, lo, hi: int) {
undo_check(s) undo_check(s)
remove_range(&s.builder.buf, lo, hi) remove_range(&s.builder.buf, lo, hi)
} }
// true if selection head and tail dont match and form a selection of multiple characters
has_selection :: proc(s: ^State) -> bool { has_selection :: proc(s: ^State) -> bool {
return s.selection[0] != s.selection[1] return s.selection[0] != s.selection[1]
} }
// return the clamped lo/hi of the current selection
// since the selection[0] moves around and could be ahead of selection[1]
// useful when rendering and needing left->right
sorted_selection :: proc(s: ^State) -> (lo, hi: int) { sorted_selection :: proc(s: ^State) -> (lo, hi: int) {
lo = min(s.selection[0], s.selection[1]) lo = min(s.selection[0], s.selection[1])
hi = max(s.selection[0], s.selection[1]) hi = max(s.selection[0], s.selection[1])
lo = clamp(lo, 0, len(s.builder.buf)) lo = clamp(lo, 0, len(s.builder.buf))
hi = clamp(hi, 0, len(s.builder.buf)) hi = clamp(hi, 0, len(s.builder.buf))
s.selection[0] = lo
s.selection[1] = hi
return return
} }
// delete the current selection range and set the proper selection afterwards
selection_delete :: proc(s: ^State) { selection_delete :: proc(s: ^State) {
lo, hi := sorted_selection(s) lo, hi := sorted_selection(s)
remove(s, lo, hi) remove(s, lo, hi)
s.selection = {lo, lo} s.selection = {lo, lo}
} }
// translates the caret position
translate_position :: proc(s: ^State, t: Translation) -> int {
translate_position :: proc(s: ^State, pos: int, t: Translation) -> int {
is_continuation_byte :: proc(b: byte) -> bool { is_continuation_byte :: proc(b: byte) -> bool {
return b >= 0x80 && b < 0xc0 return b >= 0x80 && b < 0xc0
} }
@@ -227,9 +266,7 @@ translate_position :: proc(s: ^State, pos: int, t: Translation) -> int {
} }
buf := s.builder.buf[:] buf := s.builder.buf[:]
pos := clamp(s.selection[0], 0, len(buf))
pos := pos
pos = clamp(pos, 0, len(buf))
switch t { switch t {
case .Start: case .Start:
@@ -280,6 +317,7 @@ translate_position :: proc(s: ^State, pos: int, t: Translation) -> int {
return clamp(pos, 0, len(buf)) return clamp(pos, 0, len(buf))
} }
// Moves the position of the caret (both sides of the selection)
move_to :: proc(s: ^State, t: Translation) { move_to :: proc(s: ^State, t: Translation) {
if t == .Left && has_selection(s) { if t == .Left && has_selection(s) {
lo, _ := sorted_selection(s) lo, _ := sorted_selection(s)
@@ -288,32 +326,36 @@ move_to :: proc(s: ^State, t: Translation) {
_, hi := sorted_selection(s) _, hi := sorted_selection(s)
s.selection = {hi, hi} s.selection = {hi, hi}
} else { } else {
pos := translate_position(s, s.selection[0], t) pos := translate_position(s, t)
s.selection = {pos, pos} s.selection = {pos, pos}
} }
} }
// Moves only the head of the selection and leaves the tail uneffected
select_to :: proc(s: ^State, t: Translation) { select_to :: proc(s: ^State, t: Translation) {
s.selection[0] = translate_position(s, s.selection[0], t) s.selection[0] = translate_position(s, t)
} }
// Deletes everything between the caret and resultant position
delete_to :: proc(s: ^State, t: Translation) { delete_to :: proc(s: ^State, t: Translation) {
if has_selection(s) { if has_selection(s) {
selection_delete(s) selection_delete(s)
} else { } else {
lo := s.selection[0] lo := s.selection[0]
hi := translate_position(s, lo, t) hi := translate_position(s, t)
lo, hi = min(lo, hi), max(lo, hi) lo, hi = min(lo, hi), max(lo, hi)
remove(s, lo, hi) remove(s, lo, hi)
s.selection = {lo, lo} s.selection = {lo, lo}
} }
} }
// return the currently selected text
current_selected_text :: proc(s: ^State) -> string { current_selected_text :: proc(s: ^State) -> string {
lo, hi := sorted_selection(s) lo, hi := sorted_selection(s)
return string(s.builder.buf[lo:hi]) return string(s.builder.buf[lo:hi])
} }
// copy & delete the current selection when copy() succeeds
cut :: proc(s: ^State) -> bool { cut :: proc(s: ^State) -> bool {
if copy(s) { if copy(s) {
selection_delete(s) selection_delete(s)
@@ -322,6 +364,8 @@ cut :: proc(s: ^State) -> bool {
return false return false
} }
// try and copy the currently selected text to the clipboard
// State.set_clipboard needs to be assigned
copy :: proc(s: ^State) -> bool { copy :: proc(s: ^State) -> bool {
if s.set_clipboard != nil { if s.set_clipboard != nil {
return s.set_clipboard(s.clipboard_user_data, current_selected_text(s)) return s.set_clipboard(s.clipboard_user_data, current_selected_text(s))
@@ -329,6 +373,8 @@ copy :: proc(s: ^State) -> bool {
return s.set_clipboard != nil return s.set_clipboard != nil
} }
// reinsert whatever the get_clipboard would return
// State.get_clipboard needs to be assigned
paste :: proc(s: ^State) -> bool { paste :: proc(s: ^State) -> bool {
if s.get_clipboard != nil { if s.get_clipboard != nil {
input_text(s, s.get_clipboard(s.clipboard_user_data) or_return) input_text(s, s.get_clipboard(s.clipboard_user_data) or_return)
+55 -38
View File
@@ -116,26 +116,21 @@ run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(
} }
run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T) <= size_of(rawptr) { where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
create_and_start_with_poly_data(data, fn, init_context, priority, true) create_and_start_with_poly_data(data, fn, init_context, priority, true)
} }
run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr) {
create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true) create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true)
} }
run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true) create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true)
} }
run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true) create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true)
} }
@@ -178,7 +173,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co
} }
create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T) <= size_of(rawptr) { where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T))t.data fn := cast(proc(T))t.data
assert(t.user_index >= 1) assert(t.user_index >= 1)
@@ -188,96 +183,118 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 1 t.user_index = 1
data := data data := data
mem.copy(&t.user_args[0], &data, size_of(data))
mem.copy(&t.user_args[0], &data, size_of(T))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr) {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2))t.data fn := cast(proc(T1, T2))t.data
assert(t.user_index >= 2) assert(t.user_index >= 2)
arg1 := (^T1)(&t.user_args[0])^
arg2 := (^T2)(&t.user_args[1])^ user_args := mem.slice_to_bytes(t.user_args[:])
arg1 := (^T1)(raw_data(user_args))^
arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
fn(arg1, arg2) fn(arg1, arg2)
} }
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 2 t.user_index = 2
arg1, arg2 := arg1, arg2 arg1, arg2 := arg1, arg2
mem.copy(&t.user_args[0], &arg1, size_of(arg1)) user_args := mem.slice_to_bytes(t.user_args[:])
mem.copy(&t.user_args[1], &arg2, size_of(arg2))
n := copy(user_args, mem.ptr_to_bytes(&arg1))
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg2))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3))t.data fn := cast(proc(T1, T2, T3))t.data
assert(t.user_index >= 3) assert(t.user_index >= 3)
arg1 := (^T1)(&t.user_args[0])^
arg2 := (^T2)(&t.user_args[1])^ user_args := mem.slice_to_bytes(t.user_args[:])
arg3 := (^T3)(&t.user_args[2])^ arg1 := (^T1)(raw_data(user_args))^
arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^
fn(arg1, arg2, arg3) fn(arg1, arg2, arg3)
} }
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 3 t.user_index = 3
arg1, arg2, arg3 := arg1, arg2, arg3 arg1, arg2, arg3 := arg1, arg2, arg3
mem.copy(&t.user_args[0], &arg1, size_of(arg1)) user_args := mem.slice_to_bytes(t.user_args[:])
mem.copy(&t.user_args[1], &arg2, size_of(arg2))
mem.copy(&t.user_args[2], &arg3, size_of(arg3)) n := copy(user_args, mem.ptr_to_bytes(&arg1))
n += copy(user_args[n:], mem.ptr_to_bytes(&arg2))
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg3))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3, T4))t.data fn := cast(proc(T1, T2, T3, T4))t.data
assert(t.user_index >= 4) assert(t.user_index >= 4)
arg1 := (^T1)(&t.user_args[0])^
arg2 := (^T2)(&t.user_args[1])^ user_args := mem.slice_to_bytes(t.user_args[:])
arg3 := (^T3)(&t.user_args[2])^ arg1 := (^T1)(raw_data(user_args))^
arg4 := (^T4)(&t.user_args[3])^ arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^
arg4 := (^T4)(raw_data(user_args[size_of(T1) + size_of(T2) + size_of(T3):]))^
fn(arg1, arg2, arg3, arg4) fn(arg1, arg2, arg3, arg4)
} }
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 4 t.user_index = 4
arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4 arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4
mem.copy(&t.user_args[0], &arg1, size_of(arg1)) user_args := mem.slice_to_bytes(t.user_args[:])
mem.copy(&t.user_args[1], &arg2, size_of(arg2))
mem.copy(&t.user_args[2], &arg3, size_of(arg3)) n := copy(user_args, mem.ptr_to_bytes(&arg1))
mem.copy(&t.user_args[3], &arg4, size_of(arg4)) n += copy(user_args[n:], mem.ptr_to_bytes(&arg2))
n += copy(user_args[n:], mem.ptr_to_bytes(&arg3))
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg4))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
_select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context { _select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context {
ctx, ok := init_context.? ctx, ok := init_context.?
if !ok { if !ok {
+4
View File
@@ -39,6 +39,8 @@ import nvg "vendor:nanovg"
import nvg_gl "vendor:nanovg/gl" import nvg_gl "vendor:nanovg/gl"
import fontstash "vendor:fontstash" import fontstash "vendor:fontstash"
import xlib "vendor:x11/xlib"
_ :: botan_bindings _ :: botan_bindings
_ :: botan_blake2b _ :: botan_blake2b
_ :: keccak _ :: keccak
@@ -77,3 +79,5 @@ _ :: lua_5_4
_ :: nvg _ :: nvg
_ :: nvg_gl _ :: nvg_gl
_ :: fontstash _ :: fontstash
_ :: xlib
+17 -3
View File
@@ -82,6 +82,23 @@ gb_global String target_arch_names[TargetArch_COUNT] = {
str_lit("wasm64p32"), str_lit("wasm64p32"),
}; };
gb_global String target_microarch_list[TargetArch_COUNT] = {
// TargetArch_Invalid,
str_lit("Invalid!"),
// TargetArch_amd64,
str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"),
// TargetArch_i386,
str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic,geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"),
// TargetArch_arm32,
str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"),
// TargetArch_arm64,
str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"),
// TargetArch_wasm32,
str_lit("generic"),
// TargetArch_wasm64p32,
str_lit("generic"),
};
gb_global String target_endian_names[TargetEndian_COUNT] = { gb_global String target_endian_names[TargetEndian_COUNT] = {
str_lit("little"), str_lit("little"),
str_lit("big"), str_lit("big"),
@@ -109,8 +126,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW); gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
struct TargetMetrics { struct TargetMetrics {
TargetOsKind os; TargetOsKind os;
TargetArchKind arch; TargetArchKind arch;
@@ -623,7 +638,6 @@ gb_internal TargetArchKind get_target_arch_from_string(String str) {
return TargetArch_Invalid; return TargetArch_Invalid;
} }
gb_internal bool is_excluded_target_filename(String name) { gb_internal bool is_excluded_target_filename(String name) {
String original_name = name; String original_name = name;
name = remove_extension_from_path(name); name = remove_extension_from_path(name);
+198
View File
@@ -2088,6 +2088,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
t = default_type(t); t = default_type(t);
add_type_info_type(c, t); add_type_info_type(c, t);
GB_ASSERT(t_type_info_ptr != nullptr);
add_type_info_type(c, t_type_info_ptr);
if (is_operand_value(o) && is_type_typeid(t)) { if (is_operand_value(o) && is_type_typeid(t)) {
add_package_dependency(c, "runtime", "__type_info_of"); add_package_dependency(c, "runtime", "__type_info_of");
@@ -5117,6 +5119,202 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
} }
break; break;
case BuiltinProc_type_union_tag_type:
{
if (operand->mode != Addressing_Type) {
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *u = operand->type;
if (!is_type_union(u)) {
error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
operand->mode = Addressing_Type;
operand->type = union_tag_type(u);
}
break;
case BuiltinProc_type_union_tag_offset:
{
if (operand->mode != Addressing_Type) {
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *u = operand->type;
if (!is_type_union(u)) {
error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
// NOTE(jakubtomsu): forces calculation of variant_block_size
type_size_of(u);
i64 tag_offset = u->Union.variant_block_size;
GB_ASSERT(tag_offset > 0);
operand->mode = Addressing_Constant;
operand->type = t_untyped_integer;
operand->value = exact_value_i64(tag_offset);
}
break;
case BuiltinProc_type_union_base_tag_value:
{
if (operand->mode != Addressing_Type) {
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *u = operand->type;
if (!is_type_union(u)) {
error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
operand->mode = Addressing_Constant;
operand->type = t_untyped_integer;
operand->value = exact_value_i64(u->Union.kind == UnionType_no_nil ? 0 : 1);
} break;
case BuiltinProc_type_union_variant_count:
{
if (operand->mode != Addressing_Type) {
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *u = operand->type;
if (!is_type_union(u)) {
error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
operand->mode = Addressing_Constant;
operand->type = t_untyped_integer;
operand->value = exact_value_i64(u->Union.variants.count);
} break;
case BuiltinProc_type_variant_type_of:
{
if (operand->mode != Addressing_Type) {
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *u = operand->type;
if (!is_type_union(u)) {
error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
Operand x = {};
check_expr_or_type(c, &x, ce->args[1]);
if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
error(call, "Expected a constant integer for '%.*s", LIT(builtin_name));
operand->mode = Addressing_Type;
operand->type = t_invalid;
return false;
}
i64 index = big_int_to_i64(&x.value.value_integer);
if (index < 0 || index >= u->Union.variants.count) {
error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name));
operand->mode = Addressing_Type;
operand->type = t_invalid;
return false;
}
operand->mode = Addressing_Type;
operand->type = u->Union.variants[index];
}
break;
case BuiltinProc_type_variant_index_of:
{
if (operand->mode != Addressing_Type) {
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *u = operand->type;
if (!is_type_union(u)) {
error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
Type *v = check_type(c, ce->args[1]);
u = base_type(u);
GB_ASSERT(u->kind == Type_Union);
i64 index = -1;
for_array(i, u->Union.variants) {
Type *vt = u->Union.variants[i];
if (union_variant_index_types_equal(v, vt)) {
index = i64(i);
break;
}
}
if (index < 0) {
error(operand->expr, "Expected a variant type for '%.*s'", LIT(builtin_name));
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
return false;
}
operand->mode = Addressing_Constant;
operand->type = t_untyped_integer;
operand->value = exact_value_i64(index);
}
break;
case BuiltinProc_type_struct_field_count: case BuiltinProc_type_struct_field_count:
operand->value = exact_value_i64(0); operand->value = exact_value_i64(0);
if (operand->mode != Addressing_Type) { if (operand->mode != Addressing_Type) {
+2 -5
View File
@@ -2339,7 +2339,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
ast_node(ue, UnaryExpr, node); ast_node(ue, UnaryExpr, node);
if (ast_node_expect(ue->expr, Ast_IndexExpr)) { if (ast_node_expect(ue->expr, Ast_IndexExpr)) {
ast_node(ie, IndexExpr, ue->expr); ast_node(ie, IndexExpr, ue->expr);
Type *soa_type = type_of_expr(ie->expr); Type *soa_type = type_deref(type_of_expr(ie->expr));
GB_ASSERT(is_type_soa_struct(soa_type)); GB_ASSERT(is_type_soa_struct(soa_type));
o->type = alloc_type_soa_pointer(soa_type); o->type = alloc_type_soa_pointer(soa_type);
} else { } else {
@@ -5606,9 +5606,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
for (isize i = 0; i < pt->param_count; i++) { for (isize i = 0; i < pt->param_count; i++) {
if (!visited[i]) { if (!visited[i]) {
Entity *e = pt->params->Tuple.variables[i]; Entity *e = pt->params->Tuple.variables[i];
if (is_blank_ident(e->token)) {
continue;
}
if (e->kind == Entity_Variable) { if (e->kind == Entity_Variable) {
if (e->Variable.param_value.kind != ParameterValue_Invalid) { if (e->Variable.param_value.kind != ParameterValue_Invalid) {
ordered_operands[i].mode = Addressing_Value; ordered_operands[i].mode = Addressing_Value;
@@ -7428,7 +7425,7 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
*max_count = t->Struct.soa_count; *max_count = t->Struct.soa_count;
} }
o->type = t->Struct.soa_elem; o->type = t->Struct.soa_elem;
if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) { if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable || indirection) {
o->mode = Addressing_SoaVariable; o->mode = Addressing_SoaVariable;
} else { } else {
o->mode = Addressing_Value; o->mode = Addressing_Value;
+10 -3
View File
@@ -2211,9 +2211,14 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
Entity *e = entry.value; Entity *e = entry.value;
switch (bt->Struct.soa_kind) { switch (bt->Struct.soa_kind) {
case StructSoa_Dynamic: case StructSoa_Dynamic:
add_min_dep_type_info(c, t_type_info_ptr); // append_soa
add_min_dep_type_info(c, t_allocator); add_min_dep_type_info(c, t_allocator);
/*fallthrough*/ /*fallthrough*/
case StructSoa_Slice: case StructSoa_Slice:
add_min_dep_type_info(c, t_int);
add_min_dep_type_info(c, t_uint);
/*fallthrough*/
case StructSoa_Fixed: case StructSoa_Fixed:
add_min_dep_type_info(c, alloc_type_pointer(e->type)); add_min_dep_type_info(c, alloc_type_pointer(e->type));
break; break;
@@ -6091,9 +6096,6 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("calculate global init order"); TIME_SECTION("calculate global init order");
calculate_global_init_order(c); calculate_global_init_order(c);
TIME_SECTION("check test procedures");
check_test_procedures(c);
TIME_SECTION("add type info for type definitions"); TIME_SECTION("add type info for type definitions");
add_type_info_for_type_definitions(c); add_type_info_for_type_definitions(c);
check_merge_queues_into_arrays(c); check_merge_queues_into_arrays(c);
@@ -6104,6 +6106,11 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("generate minimum dependency set"); TIME_SECTION("generate minimum dependency set");
generate_minimum_dependency_set(c, c->info.entry_point); generate_minimum_dependency_set(c, c->info.entry_point);
// NOTE(laytan): has to be ran after generate_minimum_dependency_set,
// because that collects the test procedures.
TIME_SECTION("check test procedures");
check_test_procedures(c);
TIME_SECTION("check bodies have all been checked"); TIME_SECTION("check bodies have all been checked");
check_unchecked_bodies(c); check_unchecked_bodies(c);
+13 -1
View File
@@ -260,6 +260,12 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_is_specialization_of, BuiltinProc_type_is_specialization_of,
BuiltinProc_type_is_variant_of, BuiltinProc_type_is_variant_of,
BuiltinProc_type_union_tag_type,
BuiltinProc_type_union_tag_offset,
BuiltinProc_type_union_base_tag_value,
BuiltinProc_type_union_variant_count,
BuiltinProc_type_variant_type_of,
BuiltinProc_type_variant_index_of,
BuiltinProc_type_struct_field_count, BuiltinProc_type_struct_field_count,
@@ -557,7 +563,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_union_base_tag_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_union_variant_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+27 -15
View File
@@ -21,6 +21,25 @@
#include "llvm_backend_stmt.cpp" #include "llvm_backend_stmt.cpp"
#include "llvm_backend_proc.cpp" #include "llvm_backend_proc.cpp"
char *get_default_microarchitecture() {
char * default_march = "generic";
if (build_context.metrics.arch == TargetArch_amd64) {
// NOTE(bill): x86-64-v2 is more than enough for everyone
//
// x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2
// x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
if (ODIN_LLVM_MINIMUM_VERSION_12) {
if (build_context.metrics.os == TargetOs_freestanding) {
default_march = "x86-64";
} else {
default_march = "x86-64-v2";
}
}
}
return default_march;
}
gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e) { gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e) {
if (e == nullptr) { if (e == nullptr) {
@@ -2491,7 +2510,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
} }
char const *host_cpu_name = LLVMGetHostCPUName(); char const *host_cpu_name = LLVMGetHostCPUName();
char const *llvm_cpu = "generic"; char const *llvm_cpu = get_default_microarchitecture();
char const *llvm_features = ""; char const *llvm_features = "";
if (build_context.microarch.len != 0) { if (build_context.microarch.len != 0) {
if (build_context.microarch == "native") { if (build_context.microarch == "native") {
@@ -2502,22 +2521,15 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) { if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) {
llvm_features = LLVMGetHostCPUFeatures(); llvm_features = LLVMGetHostCPUFeatures();
} }
} else if (build_context.metrics.arch == TargetArch_amd64) {
// NOTE(bill): x86-64-v2 is more than enough for everyone
//
// x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2
// x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
if (ODIN_LLVM_MINIMUM_VERSION_12) {
if (build_context.metrics.os == TargetOs_freestanding) {
llvm_cpu = "x86-64";
} else {
llvm_cpu = "x86-64-v2";
}
}
} }
// NOTE(Jeroen): Uncomment to get the list of supported microarchitectures.
/*
if (build_context.microarch == "?") {
string_set_add(&build_context.target_features_set, str_lit("+cpuhelp"));
}
*/
if (build_context.target_features_set.entries.count != 0) { if (build_context.target_features_set.entries.count != 0) {
llvm_features = target_features_set_to_cstring(permanent_allocator(), false); llvm_features = target_features_set_to_cstring(permanent_allocator(), false);
} }
+3
View File
@@ -339,6 +339,8 @@ struct lbProcedure {
bool in_multi_assignment; bool in_multi_assignment;
Array<LLVMValueRef> raw_input_parameters; Array<LLVMValueRef> raw_input_parameters;
LLVMValueRef temp_callee_return_struct_memory;
Ast *curr_stmt; Ast *curr_stmt;
Array<Scope *> scope_stack; Array<Scope *> scope_stack;
@@ -550,6 +552,7 @@ gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLV
gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile); gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile);
gb_internal gb_inline i64 lb_max_zero_init_size(void) { gb_internal gb_inline i64 lb_max_zero_init_size(void) {
return cast(i64)(4*build_context.int_size); return cast(i64)(4*build_context.int_size);
+6
View File
@@ -2939,6 +2939,12 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
} else if (is_type_soa_pointer(tv.type)) { } else if (is_type_soa_pointer(tv.type)) {
ast_node(ie, IndexExpr, ue_expr); ast_node(ie, IndexExpr, ue_expr);
lbValue addr = lb_build_addr_ptr(p, ie->expr); lbValue addr = lb_build_addr_ptr(p, ie->expr);
if (is_type_pointer(type_deref(addr.type))) {
addr = lb_emit_load(p, addr);
}
GB_ASSERT(is_type_pointer(addr.type));
lbValue index = lb_build_expr(p, ie->index); lbValue index = lb_build_expr(p, ie->index);
if (!build_context.no_bounds_check) { if (!build_context.no_bounds_check) {
+9 -3
View File
@@ -1332,6 +1332,8 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV
Type *pt = base_type(type_deref(parent.type)); Type *pt = base_type(type_deref(parent.type));
GB_ASSERT(pt->kind == Type_Union); GB_ASSERT(pt->kind == Type_Union);
if (pt->Union.kind == UnionType_shared_nil) { if (pt->Union.kind == UnionType_shared_nil) {
GB_ASSERT(type_size_of(variant_type));
lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil"); lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil");
lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil"); lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil");
lbBlock *done = lb_create_block(p, "shared_nil.done"); lbBlock *done = lb_create_block(p, "shared_nil.done");
@@ -1353,9 +1355,13 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV
} else { } else {
lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); if (type_size_of(variant_type) == 0) {
unsigned alignment = 1;
lb_emit_store(p, underlying, variant); lb_mem_zero_ptr_internal(p, parent.value, pt->Union.variant_block_size, alignment, false);
} else {
lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
lb_emit_store(p, underlying, variant);
}
lb_emit_store_union_variant_tag(p, parent, variant_type); lb_emit_store_union_variant_tag(p, parent, variant_type);
} }
} }
+19 -3
View File
@@ -1846,9 +1846,25 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
LLVMBuildRetVoid(p->builder); LLVMBuildRetVoid(p->builder);
} else { } else {
LLVMValueRef ret_val = res.value; LLVMValueRef ret_val = res.value;
ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type); LLVMTypeRef ret_type = p->abi_function_type->ret.type;
if (p->abi_function_type->ret.cast_type != nullptr) { if (LLVMTypeRef cast_type = p->abi_function_type->ret.cast_type) {
ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type); ret_type = cast_type;
}
if (LLVMGetTypeKind(ret_type) == LLVMStructTypeKind) {
LLVMTypeRef src_type = LLVMTypeOf(ret_val);
if (p->temp_callee_return_struct_memory == nullptr) {
i64 max_align = gb_max(lb_alignof(ret_type), lb_alignof(src_type));
p->temp_callee_return_struct_memory = llvm_alloca(p, ret_type, max_align);
}
// reuse the temp return value memory where possible
LLVMValueRef ptr = p->temp_callee_return_struct_memory;
LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
LLVMBuildStore(p->builder, ret_val, nptr);
ret_val = LLVMBuildLoad2(p->builder, ret_type, ptr, "");
} else {
ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
} }
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+6 -1
View File
@@ -9,7 +9,12 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_
} }
} }
if (err_on_not_found) { if (err_on_not_found) {
GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count);
for (auto const &entry : *set) {
isize type_info_index = entry.key;
gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index]));
}
GB_PANIC("NOT FOUND");
} }
return -1; return -1;
} }
+4
View File
@@ -57,6 +57,10 @@ gb_internal lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
return value; return value;
} }
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile) {
return lb_mem_zero_ptr_internal(p, ptr, LLVMConstInt(lb_type(p->module, t_uint), len, false), alignment, is_volatile);
}
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
bool is_inlinable = false; bool is_inlinable = false;
+182 -132
View File
@@ -199,19 +199,19 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
} }
gb_internal void usage(String argv0) { gb_internal void usage(String argv0) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0)); print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0));
print_usage_line(0, "Usage:"); print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:"); print_usage_line(0, "Commands:");
print_usage_line(1, "build compile directory of .odin files, as an executable."); print_usage_line(1, "build Compiles directory of .odin files, as an executable.");
print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); print_usage_line(1, " One must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse, and type check a directory of .odin files"); print_usage_line(1, "check Parses, and type checks a directory of .odin files.");
print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); print_usage_line(1, "strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program.");
print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package"); print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
print_usage_line(1, "doc generate documentation on a directory of .odin files"); print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
print_usage_line(1, "version print version"); print_usage_line(1, "version Prints version.");
print_usage_line(1, "report print information useful to reporting a bug"); print_usage_line(1, "report Prints information useful to reporting a bug.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(0, "For further details on a command, invoke command help:"); print_usage_line(0, "For further details on a command, invoke command help:");
print_usage_line(1, "e.g. `odin build -help` or `odin help build`"); print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
@@ -1580,45 +1580,45 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
gb_internal void print_show_help(String const arg0, String const &command) { gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0)); print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
print_usage_line(0, "Usage:"); print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
print_usage_line(0, ""); print_usage_line(0, "");
if (command == "build") { if (command == "build") {
print_usage_line(1, "build Compile directory of .odin files as an executable."); print_usage_line(1, "build Compiles directory of .odin files as an executable.");
print_usage_line(2, "One must contain the program's entry point, all must be in the same package."); print_usage_line(2, "One must contain the program's entry point, all must be in the same package.");
print_usage_line(2, "Use `-file` to build a single file instead."); print_usage_line(2, "Use `-file` to build a single file instead.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin build . # Build package in current directory"); print_usage_line(3, "odin build . Builds package in current directory.");
print_usage_line(3, "odin build <dir> # Build package in <dir>"); print_usage_line(3, "odin build <dir> Builds package in <dir>.");
print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point."); print_usage_line(3, "odin build filename.odin -file Builds single-file package, must contain entry point.");
} else if (command == "run") { } else if (command == "run") {
print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output."); print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin run . # Build and run package in current directory"); print_usage_line(3, "odin run . Builds and runs package in current directory.");
print_usage_line(3, "odin run <dir> # Build and run package in <dir>"); print_usage_line(3, "odin run <dir> Builds and runs package in <dir>.");
print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point."); print_usage_line(3, "odin run filename.odin -file Builds and runs single-file package, must contain entry point.");
} else if (command == "check") { } else if (command == "check") {
print_usage_line(1, "check Parse and type check directory of .odin files"); print_usage_line(1, "check Parses and type checks directory of .odin files.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin check . # Type check package in current directory"); print_usage_line(3, "odin check . Type checks package in current directory.");
print_usage_line(3, "odin check <dir> # Type check package in <dir>"); print_usage_line(3, "odin check <dir> Type checks package in <dir>.");
print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point."); print_usage_line(3, "odin check filename.odin -file Type checks single-file package, must contain entry point.");
} else if (command == "test") { } else if (command == "test") {
print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package"); print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
} else if (command == "doc") { } else if (command == "doc") {
print_usage_line(1, "doc generate documentation from a directory of .odin files"); print_usage_line(1, "doc Generates documentation from a directory of .odin files.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin doc . # Generate documentation on package in current directory"); print_usage_line(3, "odin doc . Generates documentation on package in current directory.");
print_usage_line(3, "odin doc <dir> # Generate documentation on package in <dir>"); print_usage_line(3, "odin doc <dir> Generates documentation on package in <dir>.");
print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package."); print_usage_line(3, "odin doc filename.odin -file Generates documentation on single-file package.");
} else if (command == "version") { } else if (command == "version") {
print_usage_line(1, "version print version"); print_usage_line(1, "version Prints version.");
} else if (command == "strip-semicolon") { } else if (command == "strip-semicolon") {
print_usage_line(1, "strip-semicolon"); print_usage_line(1, "strip-semicolon");
print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); print_usage_line(2, "Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project.");
} }
bool doc = command == "doc"; bool doc = command == "doc";
@@ -1642,311 +1642,318 @@ gb_internal void print_show_help(String const arg0, String const &command) {
if (doc) { if (doc) {
print_usage_line(1, "-short"); print_usage_line(1, "-short");
print_usage_line(2, "Show shortened documentation for the packages"); print_usage_line(2, "Shows shortened documentation for the packages.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-all-packages"); print_usage_line(1, "-all-packages");
print_usage_line(2, "Generates documentation for all packages used in the current project"); print_usage_line(2, "Generates documentation for all packages used in the current project.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-doc-format"); print_usage_line(1, "-doc-format");
print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)"); print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-out:<filepath>"); print_usage_line(1, "-out:<filepath>");
print_usage_line(2, "Set the file name of the outputted executable"); print_usage_line(2, "Sets the file name of the outputted executable.");
print_usage_line(2, "Example: -out:foo.exe"); print_usage_line(2, "Example: -out:foo.exe");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-o:<string>"); print_usage_line(1, "-o:<string>");
print_usage_line(2, "Set the optimization mode for compilation"); print_usage_line(2, "Sets the optimization mode for compilation.");
print_usage_line(2, "Available options:");
print_usage_line(3, "-o:none");
print_usage_line(3, "-o:minimal");
print_usage_line(3, "-o:size");
print_usage_line(3, "-o:speed");
if (LB_USE_NEW_PASS_SYSTEM) { if (LB_USE_NEW_PASS_SYSTEM) {
print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive"); print_usage_line(3, "-o:aggressive");
} else {
print_usage_line(2, "Accepted values: none, minimal, size, speed");
} }
print_usage_line(2, "Example: -o:speed"); print_usage_line(2, "The default is -o:minimal.");
print_usage_line(2, "The default is -o:minimal");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-show-timings"); print_usage_line(1, "-show-timings");
print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds"); print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-more-timings"); print_usage_line(1, "-show-more-timings");
print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds"); print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-system-calls"); print_usage_line(1, "-show-system-calls");
print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler"); print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-export-timings:<format>"); print_usage_line(1, "-export-timings:<format>");
print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`"); print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "-export-timings:json Export compile time stats to JSON"); print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
print_usage_line(3, "-export-timings:csv Export compile time stats to CSV"); print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-export-timings-file:<filename>"); print_usage_line(1, "-export-timings-file:<filename>");
print_usage_line(2, "Specify the filename for `-export-timings`"); print_usage_line(2, "Specifies the filename for `-export-timings`.");
print_usage_line(2, "Example: -export-timings-file:timings.json"); print_usage_line(2, "Example: -export-timings-file:timings.json");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-thread-count:<integer>"); print_usage_line(1, "-thread-count:<integer>");
print_usage_line(2, "Override the number of threads the compiler will use to compile with"); print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
print_usage_line(2, "Example: -thread-count:2"); print_usage_line(2, "Example: -thread-count:2");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check_only) { if (check_only) {
print_usage_line(1, "-show-unused"); print_usage_line(1, "-show-unused");
print_usage_line(2, "Shows unused package declarations within the current project"); print_usage_line(2, "Shows unused package declarations within the current project.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-unused-with-location"); print_usage_line(1, "-show-unused-with-location");
print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location"); print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-keep-temp-files"); print_usage_line(1, "-keep-temp-files");
print_usage_line(2, "Keeps the temporary files generated during compilation"); print_usage_line(2, "Keeps the temporary files generated during compilation.");
print_usage_line(0, ""); print_usage_line(0, "");
} else if (strip_semicolon) { } else if (strip_semicolon) {
print_usage_line(1, "-keep-temp-files"); print_usage_line(1, "-keep-temp-files");
print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files"); print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-collection:<name>=<filepath>"); print_usage_line(1, "-collection:<name>=<filepath>");
print_usage_line(2, "Defines a library collection used for imports"); print_usage_line(2, "Defines a library collection used for imports.");
print_usage_line(2, "Example: -collection:shared=dir/to/shared"); print_usage_line(2, "Example: -collection:shared=dir/to/shared");
print_usage_line(2, "Usage in Code:"); print_usage_line(2, "Usage in Code:");
print_usage_line(3, "import \"shared:foo\""); print_usage_line(3, "import \"shared:foo\"");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-define:<name>=<value>"); print_usage_line(1, "-define:<name>=<value>");
print_usage_line(2, "Defines a scalar boolean, integer or string as global constant"); print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
print_usage_line(2, "Example: -define:SPAM=123"); print_usage_line(2, "Example: -define:SPAM=123");
print_usage_line(2, "To use: #config(SPAM, default_value)"); print_usage_line(2, "Usage in code:");
print_usage_line(3, "#config(SPAM, default_value)");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (build) { if (build) {
print_usage_line(1, "-build-mode:<mode>"); print_usage_line(1, "-build-mode:<mode>");
print_usage_line(2, "Sets the build mode"); print_usage_line(2, "Sets the build mode.");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "-build-mode:exe Build as an executable"); print_usage_line(3, "-build-mode:exe Builds as an executable.");
print_usage_line(3, "-build-mode:dll Build as a dynamically linked library"); print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
print_usage_line(3, "-build-mode:shared Build as a dynamically linked library"); print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
print_usage_line(3, "-build-mode:obj Build as an object file"); print_usage_line(3, "-build-mode:obj Builds as an object file.");
print_usage_line(3, "-build-mode:object Build as an object file"); print_usage_line(3, "-build-mode:object Builds as an object file.");
print_usage_line(3, "-build-mode:assembly Build as an assembly file"); print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
print_usage_line(3, "-build-mode:assembler Build as an assembly file"); print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
print_usage_line(3, "-build-mode:asm Build as an assembly file"); print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file"); print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file"); print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-target:<string>"); print_usage_line(1, "-target:<string>");
print_usage_line(2, "Sets the target for the executable to be built in"); print_usage_line(2, "Sets the target for the executable to be built in.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-debug"); print_usage_line(1, "-debug");
print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'"); print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-disable-assert"); print_usage_line(1, "-disable-assert");
print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'"); print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-no-bounds-check"); print_usage_line(1, "-no-bounds-check");
print_usage_line(2, "Disables bounds checking program wide"); print_usage_line(2, "Disables bounds checking program wide.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-no-crt"); print_usage_line(1, "-no-crt");
print_usage_line(2, "Disables automatic linking with the C Run Time"); print_usage_line(2, "Disables automatic linking with the C Run Time.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-no-thread-local"); print_usage_line(1, "-no-thread-local");
print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded"); print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-lld"); print_usage_line(1, "-lld");
print_usage_line(2, "Use the LLD linker rather than the default"); print_usage_line(2, "Uses the LLD linker rather than the default.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-use-separate-modules"); print_usage_line(1, "-use-separate-modules");
print_usage_line(1, "[EXPERIMENTAL]"); print_usage_line(1, "[EXPERIMENTAL]");
print_usage_line(2, "The backend generates multiple build units which are then linked together"); print_usage_line(2, "The backend generates multiple build units which are then linked together.");
print_usage_line(2, "Normally, a single build unit is generated for a standard project"); print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-no-threaded-checker"); print_usage_line(1, "-no-threaded-checker");
print_usage_line(2, "Disabled multithreading in the semantic checker stage"); print_usage_line(2, "Disables multithreading in the semantic checker stage.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-vet"); print_usage_line(1, "-vet");
print_usage_line(2, "Do extra checks on the code"); print_usage_line(2, "Does extra checks on the code.");
print_usage_line(2, "Extra checks include:"); print_usage_line(2, "Extra checks include:");
print_usage_line(2, "-vet-unused"); print_usage_line(3, "-vet-unused");
print_usage_line(2, "-vet-shadowing"); print_usage_line(3, "-vet-shadowing");
print_usage_line(2, "-vet-using-stmt"); print_usage_line(3, "-vet-using-stmt");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-unused"); print_usage_line(1, "-vet-unused");
print_usage_line(2, "Checks for unused declarations"); print_usage_line(2, "Checks for unused declarations.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-shadowing"); print_usage_line(1, "-vet-shadowing");
print_usage_line(2, "Checks for variable shadowing within procedures"); print_usage_line(2, "Checks for variable shadowing within procedures.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-using-stmt"); print_usage_line(1, "-vet-using-stmt");
print_usage_line(2, "Checks for the use of 'using' as a statement"); print_usage_line(2, "Checks for the use of 'using' as a statement.");
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-using-param"); print_usage_line(1, "-vet-using-param");
print_usage_line(2, "Checks for the use of 'using' on procedure parameters"); print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-style"); print_usage_line(1, "-vet-style");
print_usage_line(2, "Errs on missing trailing commas followed by a newline"); print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
print_usage_line(2, "Errs on deprecated syntax"); print_usage_line(2, "Errs on deprecated syntax.");
print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)"); print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-semicolon"); print_usage_line(1, "-vet-semicolon");
print_usage_line(2, "Errs on unneeded semicolons"); print_usage_line(2, "Errs on unneeded semicolons.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-ignore-unknown-attributes"); print_usage_line(1, "-ignore-unknown-attributes");
print_usage_line(2, "Ignores unknown attributes"); print_usage_line(2, "Ignores unknown attributes.");
print_usage_line(2, "This can be used with metaprogramming tools"); print_usage_line(2, "This can be used with metaprogramming tools.");
print_usage_line(0, ""); print_usage_line(0, "");
if (command != "test") { if (command != "test") {
print_usage_line(1, "-no-entry-point"); print_usage_line(1, "-no-entry-point");
print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)"); print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
print_usage_line(0, ""); print_usage_line(0, "");
} }
} }
if (test_only) { if (test_only) {
print_usage_line(1, "-test-name:<string>"); print_usage_line(1, "-test-name:<string>");
print_usage_line(2, "Run specific test only by name"); print_usage_line(2, "Runs specific test only by name.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-minimum-os-version:<string>"); print_usage_line(1, "-minimum-os-version:<string>");
print_usage_line(2, "Sets the minimum OS version targeted by the application"); print_usage_line(2, "Sets the minimum OS version targeted by the application.");
print_usage_line(2, "e.g. -minimum-os-version:12.0.0"); print_usage_line(2, "Example: -minimum-os-version:12.0.0");
print_usage_line(2, "(Only used when target is Darwin)"); print_usage_line(2, "(Only used when target is Darwin.)");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-extra-linker-flags:<string>"); print_usage_line(1, "-extra-linker-flags:<string>");
print_usage_line(2, "Adds extra linker specific flags in a string"); print_usage_line(2, "Adds extra linker specific flags in a string.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-extra-assembler-flags:<string>"); print_usage_line(1, "-extra-assembler-flags:<string>");
print_usage_line(2, "Adds extra assembler specific flags in a string"); print_usage_line(2, "Adds extra assembler specific flags in a string.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-microarch:<string>"); print_usage_line(1, "-microarch:<string>");
print_usage_line(2, "Specifies the specific micro-architecture for the build in a string"); print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:sandybridge");
print_usage_line(3, "-microarch:native"); print_usage_line(3, "-microarch:native");
print_usage_line(3, "-microarch:? for a list");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-reloc-mode:<string>"); print_usage_line(1, "-reloc-mode:<string>");
print_usage_line(2, "Specifies the reloc mode"); print_usage_line(2, "Specifies the reloc mode.");
print_usage_line(2, "Options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "default"); print_usage_line(3, "-reloc-mode:default");
print_usage_line(3, "static"); print_usage_line(3, "-reloc-mode:static");
print_usage_line(3, "pic"); print_usage_line(3, "-reloc-mode:pic");
print_usage_line(3, "dynamic-no-pic"); print_usage_line(3, "-reloc-mode:dynamic-no-pic");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-disable-red-zone"); print_usage_line(1, "-disable-red-zone");
print_usage_line(2, "Disable red zone on a supported freestanding target"); print_usage_line(2, "Disables red zone on a supported freestanding target.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-dynamic-map-calls"); print_usage_line(1, "-dynamic-map-calls");
print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution"); print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-disallow-do"); print_usage_line(1, "-disallow-do");
print_usage_line(2, "Disallows the 'do' keyword in the project"); print_usage_line(2, "Disallows the 'do' keyword in the project.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-default-to-nil-allocator"); print_usage_line(1, "-default-to-nil-allocator");
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing"); print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-strict-style"); print_usage_line(1, "-strict-style");
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
print_usage_line(2, "Errs on missing trailing commas followed by a newline"); print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
print_usage_line(2, "Errs on deprecated syntax"); print_usage_line(2, "Errs on deprecated syntax.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-ignore-warnings"); print_usage_line(1, "-ignore-warnings");
print_usage_line(2, "Ignores warning messages"); print_usage_line(2, "Ignores warning messages.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-warnings-as-errors"); print_usage_line(1, "-warnings-as-errors");
print_usage_line(2, "Treats warning messages as error messages"); print_usage_line(2, "Treats warning messages as error messages.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-terse-errors"); print_usage_line(1, "-terse-errors");
print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line"); print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-error-pos-style:<string>"); print_usage_line(1, "-error-pos-style:<string>");
print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)"); print_usage_line(2, "Available options:");
print_usage_line(2, "'odin' file/path(45:3)"); print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
print_usage_line(2, "'unix' file/path:45:3:"); print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-max-error-count:<integer>"); print_usage_line(1, "-max-error-count:<integer>");
print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates"); print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
print_usage_line(2, "Must be an integer >0"); print_usage_line(2, "Must be an integer >0.");
print_usage_line(2, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-foreign-error-procedures"); print_usage_line(1, "-foreign-error-procedures");
print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit"); print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-sanitize:<string>"); print_usage_line(1, "-sanitize:<string>");
print_usage_line(1, "Enables sanitization analysis"); print_usage_line(2, "Enables sanitization analysis.");
print_usage_line(1, "Options are 'address', 'memory', and 'thread'"); print_usage_line(2, "Available options:");
print_usage_line(1, "NOTE: This flag can be used multiple times"); print_usage_line(3, "-sanitize:address");
print_usage_line(3, "-sanitize:memory");
print_usage_line(3, "-sanitize:thread");
print_usage_line(2, "NOTE: This flag can be used multiple times.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
@@ -1955,27 +1962,27 @@ gb_internal void print_show_help(String const arg0, String const &command) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
print_usage_line(1, "-ignore-vs-search"); print_usage_line(1, "-ignore-vs-search");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Ignores the Visual Studio search for library paths"); print_usage_line(2, "Ignores the Visual Studio search for library paths.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-resource:<filepath>"); print_usage_line(1, "-resource:<filepath>");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the resource file for the executable"); print_usage_line(2, "Defines the resource file for the executable.");
print_usage_line(2, "Example: -resource:path/to/file.rc"); print_usage_line(2, "Example: -resource:path/to/file.rc");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-pdb-name:<filepath>"); print_usage_line(1, "-pdb-name:<filepath>");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the generated PDB name when -debug is enabled"); print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
print_usage_line(2, "Example: -pdb-name:different.pdb"); print_usage_line(2, "Example: -pdb-name:different.pdb");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-subsystem:<option>"); print_usage_line(1, "-subsystem:<option>");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the subsystem for the application"); print_usage_line(2, "Defines the subsystem for the application.");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "console"); print_usage_line(3, "-subsystem:console");
print_usage_line(3, "windows"); print_usage_line(3, "-subsystem:windows");
print_usage_line(0, ""); print_usage_line(0, "");
#endif #endif
@@ -2518,6 +2525,49 @@ int main(int arg_count, char const **arg_ptr) {
// return 1; // return 1;
// } // }
// Check chosen microarchitecture. If not found or ?, print list.
bool print_microarch_list = true;
if (build_context.microarch.len == 0) {
// Autodetect, no need to print list.
print_microarch_list = false;
} else {
String march_list = target_microarch_list[build_context.metrics.arch];
String_Iterator it = {march_list, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
if (str == build_context.microarch) {
// Found matching microarch
print_microarch_list = false;
break;
}
}
}
if (print_microarch_list) {
if (build_context.microarch != "?") {
gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch));
}
gb_printf("Possible -microarch values for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch]));
gb_printf("\n");
String march_list = target_microarch_list[build_context.metrics.arch];
String_Iterator it = {march_list, 0};
String default_march = make_string_c(get_default_microarchitecture());
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
if (str == default_march) {
gb_printf("\t%.*s (default)\n", LIT(str));
} else {
gb_printf("\t%.*s\n", LIT(str));
}
}
return 0;
}
// Set and check build paths... // Set and check build paths...
if (!init_build_paths(init_filename)) { if (!init_build_paths(init_filename)) {
return 1; return 1;
+25 -1
View File
@@ -10,6 +10,10 @@ struct String {
return text[i]; return text[i];
} }
}; };
struct String_Iterator {
String const &str;
isize pos;
};
// NOTE(bill): used for printf style arguments // NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text #define LIT(x) ((int)(x).len), (x).text
#if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700 #if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700
@@ -201,11 +205,31 @@ gb_internal gb_inline String string_trim_starts_with(String const &s, String con
} }
gb_internal String string_split_iterator(String_Iterator *it, const char sep) {
isize start = it->pos;
isize end = it->str.len;
if (start == end) {
return str_lit("");
}
isize i = start;
for (; i < it->str.len; i++) {
if (it->str[i] == sep) {
String res = substring(it->str, start, i);
it->pos += res.len + 1;
return res;
}
}
it->pos = end;
return substring(it->str, start, end);
}
gb_internal gb_inline isize string_extension_position(String const &str) { gb_internal gb_inline isize string_extension_position(String const &str) {
isize dot_pos = -1; isize dot_pos = -1;
isize i = str.len; isize i = str.len;
while (i --> 0) { while (i --> 0) {
if (str[i] == GB_PATH_SEPARATOR) if (str[i] == '\\' || str[i] == '/')
break; break;
if (str[i] == '.') { if (str[i] == '.') {
dot_pos = i; dot_pos = i;
+1 -1
View File
@@ -660,7 +660,7 @@ gb_internal void futex_broadcast(Futex *addr) {
gb_internal void futex_wait(Futex *addr, Footex val) { gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) { for (;;) {
int ret = _umtx_op(addr, UMTX_OP_WAIT_UINT, val, 0, NULL); int ret = _umtx_op(addr, UMTX_OP_WAIT_UINT, val, 0, NULL);
if (ret == 0) { if (ret == -1) {
if (errno == ETIMEDOUT || errno == EINTR) { if (errno == ETIMEDOUT || errno == EINTR) {
continue; continue;
} }
+26 -3
View File
@@ -1,9 +1,26 @@
ODIN=../../odin ODIN=../../odin
PYTHON=$(shell which python3) PYTHON=$(shell which python3)
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ all: c_libc_test \
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test match_test c_libc_test net_test \ compress_test \
fmt_test crypto_test \
download_test_assets \
encoding_test \
filepath_test \
fmt_test \
hash_test \
i18n_test \
image_test \
linalg_glsl_math_test \
match_test \
math_test \
net_test \
noise_test \
os_exit_test \
reflect_test \
slice_test \
strings_test \
thread_test
download_test_assets: download_test_assets:
$(PYTHON) download_assets.py $(PYTHON) download_assets.py
@@ -44,6 +61,9 @@ filepath_test:
reflect_test: reflect_test:
$(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect $(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect
slice_test:
$(ODIN) run slice/test_core_slice.odin -file -out:test_core_slice
os_exit_test: os_exit_test:
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
@@ -61,3 +81,6 @@ net_test:
fmt_test: fmt_test:
$(ODIN) run fmt -out:test_core_fmt $(ODIN) run fmt -out:test_core_fmt
thread_test:
$(ODIN) run thread -out:test_core_thread
+10
View File
@@ -66,6 +66,11 @@ echo Running core:reflect tests
echo --- echo ---
%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b %PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b
echo ---
echo Running core:slice tests
echo ---
%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe || exit /b
echo --- echo ---
echo Running core:text/i18n tests echo Running core:text/i18n tests
echo --- echo ---
@@ -85,3 +90,8 @@ echo ---
echo Running core:container tests echo Running core:container tests
echo --- echo ---
%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b %PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b
echo ---
echo Running core:thread tests
echo ---
%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b
+63
View File
@@ -1,6 +1,7 @@
package test_core_slice package test_core_slice
import "core:slice" import "core:slice"
import "core:strings"
import "core:testing" import "core:testing"
import "core:fmt" import "core:fmt"
import "core:os" import "core:os"
@@ -30,6 +31,7 @@ when ODIN_TEST {
main :: proc() { main :: proc() {
t := testing.T{} t := testing.T{}
test_sort_with_indices(&t) test_sort_with_indices(&t)
test_binary_search(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 { if TEST_fail > 0 {
@@ -180,3 +182,64 @@ test_sort_by_indices :: proc(t: ^testing.T) {
} }
} }
} }
@test
test_binary_search :: proc(t: ^testing.T) {
builder := strings.Builder{}
defer strings.builder_destroy(&builder)
test_search :: proc(t: ^testing.T, b: ^strings.Builder, s: []i32, v: i32) -> (int, bool) {
log(t, fmt.sbprintf(b, "Searching for %v in %v", v, s))
strings.builder_reset(b)
index, found := slice.binary_search(s, v)
log(t, fmt.sbprintf(b, "index: %v, found: %v", index, found))
strings.builder_reset(b )
return index, found
}
index: int
found: bool
s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
index, found = test_search(t, &builder, s, 13)
expect(t, index == 9, "Expected index to be 9.")
expect(t, found == true, "Expected found to be true.")
index, found = test_search(t, &builder, s, 4)
expect(t, index == 7, "Expected index to be 7.")
expect(t, found == false, "Expected found to be false.")
index, found = test_search(t, &builder, s, 100)
expect(t, index == 13, "Expected index to be 13.")
expect(t, found == false, "Expected found to be false.")
index, found = test_search(t, &builder, s, 1)
expect(t, index >= 1 && index <= 4, "Expected index to be 1, 2, 3, or 4.")
expect(t, found == true, "Expected found to be true.")
index, found = test_search(t, &builder, s, -1)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == false, "Expected found to be false.")
a := []i32{}
index, found = test_search(t, &builder, a, 13)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == false, "Expected found to be false.")
b := []i32{1}
index, found = test_search(t, &builder, b, 13)
expect(t, index == 1, "Expected index to be 1.")
expect(t, found == false, "Expected found to be false.")
index, found = test_search(t, &builder, b, 1)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == true, "Expected found to be true.")
index, found = test_search(t, &builder, b, 0)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == false, "Expected found to be false.")
}
+84
View File
@@ -0,0 +1,84 @@
package test_core_thread
import "core:testing"
import "core:thread"
import "core:fmt"
import "core:os"
TEST_count := 0
TEST_fail := 0
t := &testing.T{}
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
poly_data_test(t)
if TEST_fail > 0 {
os.exit(1)
}
}
@(test)
poly_data_test :: proc(_t: ^testing.T) {
MAX :: size_of(rawptr) * thread.MAX_USER_ARGUMENTS
@static poly_data_test_t: ^testing.T
poly_data_test_t = _t
b: [MAX]byte = 8
t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) {
b_expect: [MAX]byte = 8
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
})
defer free(t1)
b1: [3]uintptr = 1
b2: [MAX / 2]byte = 3
t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) {
b_expect: [3]uintptr = 1
b2_expect: [MAX / 2]byte = 3
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct")
})
defer free(t2)
t3 := thread.create_and_start_with_poly_data3(b1, b2, uintptr(333), proc(b: [3]uintptr, b2: [MAX / 2]byte, b3: uintptr) {
b_expect: [3]uintptr = 1
b2_expect: [MAX / 2]byte = 3
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct")
expect(poly_data_test_t, b3 == 333, "thread poly data not correct")
})
defer free(t3)
t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) {
b_expect: [3]uintptr = 1
expect(poly_data_test_t, n == 111, "thread poly data not correct")
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
expect(poly_data_test_t, n2 == 333, "thread poly data not correct")
expect(poly_data_test_t, n4 == 5, "thread poly data not correct")
})
defer free(t4)
thread.join_multiple(t1, t2, t3, t4)
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+8 -21
View File
@@ -16,23 +16,9 @@ when ODIN_OS == .Windows {
} }
} else when ODIN_OS == .Linux { } else when ODIN_OS == .Linux {
when RAYGUI_SHARED { when RAYGUI_SHARED {
// Note(bumbread): can't panic here, because the users might be expecting to foreign import lib "linux/libraygui.so"
// only use raylib. Let's have them get the error at link-time instead..
//#panic("Cannot link libraygui.so: not in the vendor collection")
// Note(bumbread): unless we import something the rest of the bindings will
// make a compile-time error. This is a bit ugly for now, but in the future
// raygui probably needs to be in a separate package.
foreign import lib {"_"}
} else { } else {
// #panic("Cannot link libraygui.a: not in the vendor collection") foreign import lib "linux/libraygui.a"
// TODO(bumbread): apparently this one was missing. This might need
// to get rebuilt for linux
// foreign import lib {
// "linux/libraygui.a",
// // "system:dl",
// // "system:pthread",
// }
foreign import lib {"_"}
} }
} else when ODIN_OS == .Darwin { } else when ODIN_OS == .Darwin {
when ODIN_ARCH == .arm64 { when ODIN_ARCH == .arm64 {
@@ -238,6 +224,7 @@ SCROLLBAR_RIGHT_SIDE :: 1
@(default_calling_convention="c") @(default_calling_convention="c")
foreign lib { foreign lib {
@(link_name="raylib_version") version: cstring
// Global gui state control functions // Global gui state control functions
GuiEnable :: proc() --- // Enable gui controls (global state) GuiEnable :: proc() --- // Enable gui controls (global state)
@@ -293,17 +280,17 @@ foreign lib {
// Basic controls set // Basic controls set
GuiLabel :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label control, shows text GuiLabel :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label control, shows text
GuiButton :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Button control, returns true when clicked GuiButton :: proc(bounds: Rectangle, text: cstring) -> bool --- // Button control, returns true when clicked
GuiLabelButton :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label button control, show true when clicked GuiLabelButton :: proc(bounds: Rectangle, text: cstring) -> bool --- // Label button control, show true when clicked
GuiToggle :: proc(bounds: Rectangle, text: cstring, active: ^bool) -> c.int --- // Toggle Button control, returns true when active GuiToggle :: proc(bounds: Rectangle, text: cstring, active: ^bool) -> c.int --- // Toggle Button control, returns true when active
GuiToggleGroup :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Toggle Group control, returns active toggle index GuiToggleGroup :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Toggle Group control, returns active toggle index
GuiCheckBox :: proc(bounds: Rectangle, text: cstring, checked: ^bool) -> c.int --- // Check Box control, returns true when active GuiCheckBox :: proc(bounds: Rectangle, text: cstring, checked: ^bool) -> bool --- // Check Box control, returns true when active
GuiComboBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Combo Box control, returns selected item index GuiComboBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Combo Box control, returns selected item index
GuiDropdownBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int, editMode: bool) -> c.int --- // Dropdown Box control, returns selected item GuiDropdownBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int, editMode: bool) -> bool --- // Dropdown Box control, returns selected item
GuiSpinner :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Spinner control, returns selected value GuiSpinner :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Spinner control, returns selected value
GuiValueBox :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Value Box control, updates input text with numbers GuiValueBox :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Value Box control, updates input text with numbers
GuiTextBox :: proc(bounds: Rectangle, text: cstring, textSize: c.int, editMode: bool) -> c.int --- // Text Box control, updates input text GuiTextBox :: proc(bounds: Rectangle, text: cstring, textSize: c.int, editMode: bool) -> bool --- // Text Box control, updates input text
GuiSlider :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider control, returns selected value GuiSlider :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider control, returns selected value
GuiSliderBar :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider Bar control, returns selected value GuiSliderBar :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider Bar control, returns selected value
+4
View File
@@ -0,0 +1,4 @@
# TODO(flysand): Remove this file.
*.i
+651
View File
@@ -0,0 +1,651 @@
//+build linux, freebsd, openbsd
package xlib
// Special values for many types. Most of these constants
// aren't attached to a specific type.
None :: 0
ParentRelative :: 1
CopyFromParent :: 0
PointerWindow :: 0
InputFocus :: 1
PointerRoot :: 1
AnyPropertyType :: 0
AnyKey :: 0
AnyButton :: 0
AllTemporary :: 0
CurrentTime :: 0
NoSymbol :: 0
XA_WM_CLASS :: Atom(67)
XA_WM_CLIENT_MACHINE :: Atom(36)
XA_WM_COMMAND :: Atom(34)
XA_WM_HINTS :: Atom(35)
XA_WM_ICON_NAME :: Atom(37)
XA_WM_ICON_SIZE :: Atom(38)
XA_WM_NAME :: Atom(39)
XA_WM_NORMAL_HINTS :: Atom(40)
XA_WM_SIZE_HINTS :: Atom(41)
XA_WM_TRANSIENT_FOR :: Atom(68)
XA_WM_ZOOM_HINTS :: Atom(42)
// NOTE(flysand): Some implementations return Status as enum, other return it
// as an integer. I will make it a status.
Status :: enum i32 {
Success = 0,
BadRequest = 1,
BadValue = 2,
BadWindow = 3,
BadPixmap = 4,
BadAtom = 5,
BadCursor = 6,
BadFont = 7,
BadMatch = 8,
BadDrawable = 9,
BadAccess = 10,
BadAlloc = 11,
BadColor = 12,
BadGC = 13,
BadIDChoice = 14,
BadName = 15,
BadLength = 16,
BadImplementation = 17,
FirstExtensionError = 128,
LastExtensionError = 255,
}
ByteOrder :: enum i32 {
LSBFirst = 0,
MSBFirst = 1,
}
Gravity :: enum i32 {
ForgetGravity = 0,
UnmapGravity = 0,
NorthWestGravity = 1,
NorthGravity = 2,
NorthEastGravity = 3,
WestGravity = 4,
CenterGravity = 5,
EastGravity = 6,
SouthWestGravity = 7,
SouthGravity = 8,
SouthEastGravity = 9,
StaticGravity = 10,
}
BackingStore :: enum i32 {
NotUseful = 0,
WhenMapped = 1,
Always = 2,
}
MouseButton :: enum i32 {
Button1 = 1,
Button2 = 2,
Button3 = 3,
Button4 = 4,
Button5 = 5,
}
EventMask :: bit_set[EventMaskBits; int]
EventMaskBits :: enum i32 {
KeyPress = 0,
KeyRelease = 1,
ButtonPress = 2,
ButtonRelease = 3,
EnterWindow = 4,
LeaveWindow = 5,
PointerMotion = 6,
PointerMotionHint = 7,
Button1Motion = 8,
Button2Motion = 9,
Button3Motion = 10,
Button4Motion = 11,
Button5Motion = 12,
ButtonMotion = 13,
KeymapState = 14,
Exposure = 15,
VisibilityChange = 16,
StructureNotify = 17,
ResizeRedirect = 18,
SubstructureNotify = 19,
SubstructureRedirect = 20,
FocusChange = 21,
PropertyChange = 22,
ColormapChange = 23,
OwnerGrabButton = 24,
}
EventType :: enum i32 {
KeyPress = 2,
KeyRelease = 3,
ButtonPress = 4,
ButtonRelease = 5,
MotionNotify = 6,
EnterNotify = 7,
LeaveNotify = 8,
FocusIn = 9,
FocusOut = 10,
KeymapNotify = 11,
Expose = 12,
GraphicsExpose = 13,
NoExpose = 14,
VisibilityNotify = 15,
CreateNotify = 16,
DestroyNotify = 17,
UnmapNotify = 18,
MapNotify = 19,
MapRequest = 20,
ReparentNotify = 21,
ConfigureNotify = 22,
ConfigureRequest = 23,
GravityNotify = 24,
ResizeRequest = 25,
CirculateNotify = 26,
CirculateRequest = 27,
PropertyNotify = 28,
SelectionClear = 29,
SelectionRequest = 30,
SelectionNotify = 31,
ColormapNotify = 32,
ClientMessage = 33,
MappingNotify = 34,
GenericEvent = 35,
}
InputMask :: bit_set[InputMaskBits; i32]
InputMaskBits :: enum {
ShiftMask = 0,
LockMask = 1,
ControlMask = 2,
Mod1Mask = 3,
Mod2Mask = 4,
Mod3Mask = 5,
Mod4Mask = 6,
Mod5Mask = 7,
Button1Mask = 8,
Button2Mask = 9,
Button3Mask = 10,
Button4Mask = 11,
Button5Mask = 12,
AnyModifier = 15,
}
NotifyMode :: enum i32 {
NotifyNormal = 0,
NotifyGrab = 1,
NotifyUngrab = 2,
NotifyWhileGrabbed = 3,
}
NotifyDetail :: enum i32 {
NotifyAncestor = 0,
NotifyVirtual = 1,
NotifyInferior = 2,
NotifyNonlinear = 3,
NotifyNonlinearVirtual = 4,
NotifyPointer = 5,
NotifyPointerRoot = 6,
NotifyDetailNone = 7,
}
MappingRequest :: enum i32 {
MappingModifier = 0,
MappingKeyboard = 1,
MappingPointer = 2,
}
VisibilityState :: enum i32 {
VisibilityUnobscured = 0,
VisibilityPartiallyObscured = 1,
VisibilityFullyObscured = 2,
}
ColormapState :: enum i32 {
ColormapUninstalled = 0,
ColormapInstalled = 1,
}
PropertyState :: enum i32 {
PropertyNewValue = 0,
PropertyDelete = 1,
}
CloseMode :: enum i32 {
DestroyAll = 0,
RetainPermanent = 1,
RetainTemporary = 2,
}
EventQueueMode :: enum i32 {
QueuedAlready = 0,
QueuedAfterReading = 1,
QueuedAfterFlush = 2,
}
WindowAttributeMask :: bit_set[WindowAttributeMaskBits; int]
WindowAttributeMaskBits :: enum {
CWBackPixmap = 0,
CWBackPixel = 1,
CWBorderPixmap = 2,
CWBorderPixel = 3,
CWBitGravity = 4,
CWWinGravity = 5,
CWBackingStore = 6,
CWBackingPlanes = 7,
CWBackingPixel = 8,
CWOverrideRedirect = 9,
CWSaveUnder = 10,
CWEventMask = 11,
CWDontPropagate = 12,
CWColormap = 13,
CWCursor = 14,
}
WindowClass :: enum i32 {
CopyFromParent = 0,
InputOutput = 1,
InputOnly = 2,
}
WindowChangesMask :: bit_set[WindowChangesMaskBits; i32]
WindowChangesMaskBits :: enum {
CWX = 0,
CWY = 1,
CWWidth = 2,
CWHeight = 3,
CWBorderWidth = 4,
CWSibling = 5,
CWStackMode = 6,
}
WindowStacking :: enum i32 {
Above = 0,
Below = 1,
TopIf = 2,
BottomIf = 3,
Opposite = 4,
}
CirculationDirection :: enum i32 {
RaiseLowest = 0,
LowerHighest = 1,
}
CirculationRequest :: enum i32 {
PlaceOnTop = 0,
PlaceOnBottom = 1,
}
WindowMapState :: enum i32 {
IsUnmapped = 0,
IsUnviewable = 1,
IsViewable = 2,
}
KeyMask :: enum u32 {
ShiftMask = 0,
LockMask = 1,
ControlMask = 2,
Mod1Mask = 3,
Mod2Mask = 4,
Mod3Mask = 5,
Mod4Mask = 6,
Mod5Mask = 7,
}
CursorShape :: enum u32 {
XC_X_cursor = 0,
XC_arrow = 2,
XC_based_arrow_down = 4,
XC_based_arrow_up = 6,
XC_boat = 8,
XC_bogosity = 10,
XC_bottom_left_corner = 12,
XC_bottom_right_corner = 14,
XC_bottom_side = 16,
XC_bottom_tee = 18,
XC_box_spiral = 20,
XC_center_ptr = 22,
XC_circle = 24,
XC_clock = 26,
XC_coffee_mug = 28,
XC_cross = 30,
XC_cross_reverse = 32,
XC_crosshair = 34,
XC_diamond_cross = 36,
XC_dot = 38,
XC_dotbox = 40,
XC_double_arrow = 42,
XC_draft_large = 44,
XC_draft_small = 46,
XC_draped_box = 48,
XC_exchange = 50,
XC_fleur = 52,
XC_gobbler = 54,
XC_gumby = 56,
XC_hand1 = 58,
XC_hand2 = 60,
XC_heart = 62,
XC_icon = 64,
XC_iron_cross = 66,
XC_left_ptr = 68,
XC_left_side = 70,
XC_left_tee = 72,
XC_leftbutton = 74,
XC_ll_angle = 76,
XC_lr_angle = 78,
XC_man = 80,
XC_middlebutton = 82,
XC_mouse = 84,
XC_pencil = 86,
XC_pirate = 88,
XC_plus = 90,
XC_question_arrow = 92,
XC_right_ptr = 94,
XC_right_side = 96,
XC_right_tee = 98,
XC_rightbutton = 100,
XC_rtl_logo = 102,
XC_sailboat = 104,
XC_sb_down_arrow = 106,
XC_sb_h_double_arrow = 108,
XC_sb_left_arrow = 110,
XC_sb_right_arrow = 112,
XC_sb_up_arrow = 114,
XC_sb_v_double_arrow = 116,
XC_shuttle = 118,
XC_sizing = 120,
XC_spider = 122,
XC_spraycan = 124,
XC_star = 126,
XC_target = 128,
XC_tcross = 130,
XC_top_left_arrow = 132,
XC_top_left_corner = 134,
XC_top_right_corner = 136,
XC_top_side = 138,
XC_top_tee = 140,
XC_trek = 142,
XC_ul_angle = 144,
XC_umbrella = 146,
XC_ur_angle = 148,
XC_watch = 150,
XC_xterm = 152,
XC_num_glyphs = 154,
}
ColorFormat :: enum u32 {
XcmsUndefinedFormat = 0x00000000,
XcmsCIEXYZFormat = 0x00000001,
XcmsCIEuvYFormat = 0x00000002,
XcmsCIExyYFormat = 0x00000003,
XcmsCIELabFormat = 0x00000004,
XcmsCIELuvFormat = 0x00000005,
XcmsTekHVCFormat = 0x00000006,
XcmsRGBFormat = 0x80000000,
XcmsRGBiFormat = 0x80000001,
}
ColormapAlloc :: enum i32 {
AllocNone = 0,
AllocAll = 1,
}
ColorFlags :: bit_set[ColorFlagsBits; i32]
ColorFlagsBits :: enum {
DoRed = 0,
DoGreen = 1,
DoBlue = 2,
}
GCAttributeMask :: bit_set[GCAttributeMaskBits; uint]
GCAttributeMaskBits :: enum {
GCFunction = 0,
GCPlaneMask = 1,
GCForeground = 2,
GCBackground = 3,
GCLineWidth = 4,
GCLineStyle = 5,
GCCapStyle = 6,
GCJoinStyle = 7,
GCFillStyle = 8,
GCFillRule = 9,
GCTile = 10,
GCStipple = 11,
GCTileStipXOrigin = 12,
GCTileStipYOrigin = 13,
GCFont = 14,
GCSubwindowMode = 15,
GCGraphicsExposures= 16,
GCClipXOrigin = 17,
GCClipYOrigin = 18,
GCClipMask = 19,
GCDashOffset = 20,
GCDashList = 21,
GCArcMode = 22,
}
GCFunction :: enum i32 {
GXclear = 0x0, // 0
GXand = 0x1, // src & dst
GXandReverse = 0x2, // src & ~dst
GXcopy = 0x3, // src
GXandInverted = 0x4, // ~src & dst
GXnoop = 0x5, // dst
GXxor = 0x6, // src ~ dst
GXor = 0x7, // src | dst
GXnor = 0x8, // ~src & ~dst
GXequiv = 0x9, // ~src ~ dst
GXinvert = 0xa, // ~dst
GXorReverse = 0xb, // src | ~dst
GXcopyInverted = 0xc, // ~src
GXorInverted = 0xd, // ~src | dst
GXnand = 0xe, // ~src | ~dst
GXset = 0xf, // 1
}
LineStyle :: enum i32 {
LineSolid = 0,
LineOnOffDash = 1,
LineDoubleDash = 2,
}
CapStyle :: enum i32 {
CapNotLast = 0,
CapButt = 1,
CapRound = 2,
CapProjecting = 3,
}
JoinStyle :: enum i32 {
JoinMiter = 0,
JoinRound = 1,
JoinBevel = 2,
}
FillStyle :: enum i32 {
FillSolid = 0,
FillTiled = 1,
FillStippled = 2,
FillOpaqueStippled = 3,
}
FillRule :: enum i32 {
EvenOddRule = 0,
WindingRule = 1,
}
ArcMode :: enum i32 {
ArcChord = 0,
ArcPieSlice = 1,
}
SubwindowMode :: enum i32 {
ClipByChildren = 0,
IncludeInferiors = 1,
}
CoordMode :: enum i32 {
CoordModeOrigin = 0,
CoordModePrevious = 1,
}
Shape :: enum i32 {
Complex = 0,
Nonconvex = 1,
Convex = 2,
}
FontDirection :: enum i32 {
FontLeftToRight = 0,
FontRightToLeft = 1,
}
ImageFormat :: enum i32 {
XYBitmap = 0,
XYPixmap = 1,
ZPixmap = 2,
}
SaveSetChangeMode :: enum i32 {
SetModeInsert = 0,
SetModeDelete = 1,
}
ScreenSaverBlanking :: enum i32 {
DontPreferBlanking = 0,
PreferBlanking = 1,
DefaultBlanking = 2,
}
ScreenSavingExposures :: enum i32 {
DontAllowExposures = 0,
AllowExposures = 1,
DefaultExposures = 2,
}
ScreenSaverForceMode :: enum i32 {
ScreenSaverReset = 0,
ScreenSaverActive = 1,
}
AccessControlMode :: enum i32 {
DisableAccess = 0,
EnableAccess = 1,
}
GrabMode :: enum i32 {
GrabModeSync = 0,
GrabModeAsync = 1,
}
AllowEventsMode :: enum i32 {
AsyncPointer = 0,
SyncPointer = 1,
ReplayPointer = 2,
AsyncKeyboard = 3,
SyncKeyboard = 4,
ReplayKeyboard = 5,
AsyncBoth = 6,
SyncBoth = 7,
}
FocusRevert :: enum i32 {
RevertToNone = 0,
RevertToPointerRoot = 1,
RevertToParent = 2,
}
KeyboardControlMask :: bit_set[KeyboardControlMaskBits; int]
KeyboardControlMaskBits :: enum {
KBKeyClickPercent = 0,
KBBellPercent = 1,
KBBellPitch = 2,
KBBellDuration = 3,
KBLed = 4,
KBLedMode = 5,
KBKey = 6,
KBAutoRepeatMode = 7,
}
KeyboardAutoRepeatMode :: enum i32 {
AutoRepeatModeOff = 0,
AutoRepeatModeOn = 1,
AutoRepeatModeDefault = 2,
}
KeyboardLedMode :: enum i32 {
LedModeOff = 0,
LedModeOn = 1,
}
WMHints :: bit_set[WMHintsBits; uint]
WMHintsBits :: enum {
InputHint = 0,
StateHint = 1,
IconPixmapHint = 2,
IconWindowHint = 3,
IconPositionHint = 4,
IconMaskHint = 5,
WindowGroupHint = 6,
XUrgencyHint = 8,
}
WMHintState :: enum i32 {
WithdrawnState = 0,
NormalState = 1,
IconicState = 3,
}
AllHints :: WMHints{
.InputHint,
.StateHint,
.IconPixmapHint,
.IconWindowHint,
.IconPositionHint,
.IconMaskHint,
.WindowGroupHint,
}
SizeHints :: bit_set[SizeHintsBits; uint]
SizeHintsBits :: enum {
USPosition = 0,
USSize = 1,
PPosition = 2,
PSize = 3,
PMinSize = 4,
PMaxSize = 5,
PResizeInc = 6,
PAspect = 7,
PBaseSize = 8,
PWinGravity = 9,
}
VisualInfoMask :: bit_set[VisualInfoMaskBits; int]
VisualInfoMaskBits :: enum {
VisualIDMask = 0,
VisualScreenMask = 1,
VisualDepthMask = 2,
VisualClassMask = 3,
VisualRedMaskMask = 4,
VisualGreenMaskMask = 5,
VisualBlueMaskMask = 6,
VisualColormapSizeMask = 7,
VisualBitsPerRGBMask = 8,
}
VisualNoMask :: VisualInfoMask {}
VisualAllMask :: VisualInfoMask {
.VisualIDMask,
.VisualScreenMask,
.VisualDepthMask,
.VisualClassMask,
.VisualRedMaskMask,
.VisualGreenMaskMask,
.VisualBlueMaskMask,
.VisualColormapSizeMask,
.VisualBitsPerRGBMask,
}
+1681
View File
File diff suppressed because it is too large Load Diff
+1908
View File
File diff suppressed because it is too large Load Diff
+1307
View File
File diff suppressed because it is too large Load Diff