mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 12:48:14 +00:00
Merge branch 'master' into master
This commit is contained in:
@@ -130,10 +130,15 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
}
|
||||
|
||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
delta := int(k/4);
|
||||
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
|
||||
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
|
||||
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310;
|
||||
capacity := int(f64(k)*log10_2 + 1);
|
||||
|
||||
r := a.count; // read index
|
||||
w := a.count+delta; // write index
|
||||
r := a.count; // read index
|
||||
w := a.count+capacity; // write index
|
||||
|
||||
d := len(a.digits);
|
||||
|
||||
n: uint;
|
||||
for r -= 1; r >= 0; r -= 1 {
|
||||
@@ -141,7 +146,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
quo := n/10;
|
||||
rem := n - 10*quo;
|
||||
w -= 1;
|
||||
if w < len(a.digits) {
|
||||
if w < d {
|
||||
a.digits[w] = byte('0' + rem);
|
||||
} else if rem != 0 {
|
||||
a.trunc = true;
|
||||
@@ -153,7 +158,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
quo := n/10;
|
||||
rem := n - 10*quo;
|
||||
w -= 1;
|
||||
if 0 <= w && w < len(a.digits) {
|
||||
if w < d {
|
||||
a.digits[w] = byte('0' + rem);
|
||||
} else if rem != 0 {
|
||||
a.trunc = true;
|
||||
@@ -161,9 +166,12 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
n = quo;
|
||||
}
|
||||
|
||||
a.count += delta;
|
||||
a.count = min(a.count, len(a.digits));
|
||||
a.decimal_point += delta;
|
||||
// NOTE(bill): Remove unused buffer size
|
||||
assert(w >= 0);
|
||||
capacity -= w;
|
||||
|
||||
a.count = min(a.count+capacity, d);
|
||||
a.decimal_point += capacity;
|
||||
trim(a);
|
||||
}
|
||||
|
||||
@@ -253,3 +261,4 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
+18
-20
@@ -2,8 +2,6 @@ package cel;
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
import "core:os"
|
||||
import "core:mem"
|
||||
import "core:unicode/utf8"
|
||||
import "core:strings"
|
||||
|
||||
@@ -34,7 +32,7 @@ Parser :: struct {
|
||||
|
||||
print_value :: proc(value: Value, pretty := true, indent := 0) {
|
||||
print_indent :: proc(indent: int) {
|
||||
for i in 0..indent-1 do fmt.print("\t");
|
||||
for _ in 0..indent-1 do fmt.print("\t");
|
||||
}
|
||||
|
||||
switch v in value {
|
||||
@@ -62,16 +60,16 @@ print_value :: proc(value: Value, pretty := true, indent := 0) {
|
||||
if pretty do fmt.println();
|
||||
|
||||
i := 0;
|
||||
for name, value in v {
|
||||
for name, val in v {
|
||||
if pretty {
|
||||
print_indent(indent+1);
|
||||
fmt.printf("%s = ", name);
|
||||
print_value(value, pretty, indent+1);
|
||||
print_value(val, pretty, indent+1);
|
||||
fmt.println(",");
|
||||
} else {
|
||||
if i > 0 do fmt.print(", ");
|
||||
fmt.printf("%s = ", name);
|
||||
print_value(value, pretty, indent+1);
|
||||
print_value(val, pretty, indent+1);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +153,7 @@ destroy :: proc(p: ^Parser) {
|
||||
delete(v);
|
||||
|
||||
case Dict:
|
||||
for key, value in v do destroy_value(value);
|
||||
for _, dv in v do destroy_value(dv);
|
||||
delete(v);
|
||||
}
|
||||
}
|
||||
@@ -201,11 +199,12 @@ unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool,
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
w: int;
|
||||
|
||||
if s[0] == quote && quote == '"' {
|
||||
return;
|
||||
} else if s[0] >= 0x80 {
|
||||
r, w := utf8.decode_rune_in_string(s);
|
||||
r, w = utf8.decode_rune_in_string(s);
|
||||
return r, true, s[w:], true;
|
||||
} else if s[0] != '\\' {
|
||||
return rune(s[0]), false, s[1:], true;
|
||||
@@ -291,7 +290,6 @@ unquote_string :: proc(p: ^Parser, t: Token) -> (string, bool) {
|
||||
return t.lit, true;
|
||||
}
|
||||
s := t.lit;
|
||||
n := len(s);
|
||||
quote := '"';
|
||||
|
||||
if s == `""` {
|
||||
@@ -442,7 +440,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
|
||||
|
||||
case Kind.Open_Paren:
|
||||
expect_token(p, Kind.Open_Paren);
|
||||
expr, pos := parse_expr(p);
|
||||
expr, _ := parse_expr(p);
|
||||
expect_token(p, Kind.Close_Paren);
|
||||
return expr, tok.pos;
|
||||
|
||||
@@ -451,7 +449,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
|
||||
elems := make([dynamic]Value, 0, 4);
|
||||
for p.curr_token.kind != Kind.Close_Bracket &&
|
||||
p.curr_token.kind != Kind.EOF {
|
||||
elem, pos := parse_expr(p);
|
||||
elem, _ := parse_expr(p);
|
||||
append(&elems, elem);
|
||||
|
||||
if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" {
|
||||
@@ -481,9 +479,9 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
|
||||
name, ok := unquote_string(p, name_tok);
|
||||
if !ok do error(p, tok.pos, "Unable to unquote string");
|
||||
expect_token(p, Kind.Assign);
|
||||
elem, pos := parse_expr(p);
|
||||
elem, _ := parse_expr(p);
|
||||
|
||||
if _, ok := dict[name]; ok {
|
||||
if _, ok2 := dict[name]; ok2 {
|
||||
error(p, name_tok.pos, "Previous declaration of %s in this scope", name);
|
||||
} else {
|
||||
dict[name] = elem;
|
||||
@@ -533,9 +531,9 @@ parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) {
|
||||
}
|
||||
|
||||
case Kind.Open_Bracket:
|
||||
open := expect_token(p, Kind.Open_Bracket);
|
||||
expect_token(p, Kind.Open_Bracket);
|
||||
index, index_pos := parse_expr(p);
|
||||
close := expect_token(p, Kind.Close_Bracket);
|
||||
expect_token(p, Kind.Close_Bracket);
|
||||
|
||||
|
||||
switch a in operand {
|
||||
@@ -613,7 +611,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) {
|
||||
|
||||
case Kind.Not:
|
||||
next_token(p);
|
||||
expr, pos := parse_unary_expr(p);
|
||||
expr, _ := parse_unary_expr(p);
|
||||
if v, ok := expr.(bool); ok {
|
||||
return !v, op.pos;
|
||||
}
|
||||
@@ -757,9 +755,9 @@ parse_binary_expr :: proc(p: ^Parser, prec_in: int) -> (Value, Pos) {
|
||||
|
||||
if op.kind == Kind.Question {
|
||||
cond := expr;
|
||||
x, x_pos := parse_expr(p);
|
||||
x, _ := parse_expr(p);
|
||||
expect_token(p, Kind.Colon);
|
||||
y, y_pos := parse_expr(p);
|
||||
y, _ := parse_expr(p);
|
||||
|
||||
if t, ok := cond.(bool); ok {
|
||||
expr = t ? x : y;
|
||||
@@ -824,9 +822,9 @@ parse_assignment :: proc(p: ^Parser) -> bool {
|
||||
expect_token(p, Kind.Assign);
|
||||
name, ok := unquote_string(p, tok);
|
||||
if !ok do error(p, tok.pos, "Unable to unquote string");
|
||||
expr, pos := parse_expr(p);
|
||||
expr, _ := parse_expr(p);
|
||||
d := top_dict(p);
|
||||
if _, ok := d[name]; ok {
|
||||
if _, ok2 := d[name]; ok2 {
|
||||
error(p, tok.pos, "Previous declaration of %s", name);
|
||||
} else {
|
||||
d[name] = expr;
|
||||
|
||||
@@ -322,7 +322,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
||||
}
|
||||
|
||||
if t.curr_rune == '0' {
|
||||
offset := t.offset;
|
||||
offset = t.offset;
|
||||
advance_to_next_rune(t);
|
||||
switch t.curr_rune {
|
||||
case 'b', 'B':
|
||||
@@ -403,17 +403,17 @@ scan :: proc(t: ^Tokenizer) -> Token {
|
||||
quote := r;
|
||||
tok = String;
|
||||
for {
|
||||
r := t.curr_rune;
|
||||
if r == '\n' || r < 0 {
|
||||
this_r := t.curr_rune;
|
||||
if this_r == '\n' || r < 0 {
|
||||
token_error(t, "String literal not terminated");
|
||||
break;
|
||||
}
|
||||
advance_to_next_rune(t);
|
||||
if r == quote {
|
||||
if this_r == quote {
|
||||
break;
|
||||
}
|
||||
// TODO(bill); Handle properly
|
||||
if r == '\\' && t.curr_rune == quote {
|
||||
if this_r == '\\' && t.curr_rune == quote {
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
}
|
||||
|
||||
+125
-21
@@ -10,7 +10,7 @@ import "core:strconv"
|
||||
import "core:strings"
|
||||
|
||||
|
||||
@(private)
|
||||
@private
|
||||
DEFAULT_BUFFER_SIZE :: 1<<12;
|
||||
|
||||
Info :: struct {
|
||||
@@ -31,6 +31,7 @@ Info :: struct {
|
||||
|
||||
buf: ^strings.Builder,
|
||||
arg: any, // Temporary
|
||||
record_level: int,
|
||||
}
|
||||
|
||||
fprint :: proc(fd: os.Handle, args: ..any) -> int {
|
||||
@@ -551,9 +552,6 @@ _pad :: proc(fi: ^Info, s: string) {
|
||||
|
||||
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||
switch verb {
|
||||
// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
|
||||
// case 'f', 'F', 'v':
|
||||
|
||||
case 'f', 'F', 'v':
|
||||
prec: int = 3;
|
||||
if fi.prec_set do prec = fi.prec;
|
||||
@@ -588,6 +586,59 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||
_pad(fi, str[1:]);
|
||||
}
|
||||
|
||||
case 'e', 'E':
|
||||
prec: int = 3;
|
||||
if fi.prec_set do prec = fi.prec;
|
||||
buf: [386]byte;
|
||||
|
||||
str := strconv.append_float(buf[1:], v, 'e', prec, bit_size);
|
||||
str = string(buf[:len(str)+1]);
|
||||
if str[1] == '+' || str[1] == '-' {
|
||||
str = str[1:];
|
||||
} else {
|
||||
str[0] = '+';
|
||||
}
|
||||
|
||||
if fi.space && !fi.plus && str[0] == '+' {
|
||||
str[0] = ' ';
|
||||
}
|
||||
|
||||
if len(str) > 1 && (str[1] == 'N' || str[1] == 'I') {
|
||||
strings.write_string(fi.buf, str);
|
||||
return;
|
||||
}
|
||||
|
||||
if fi.plus || str[0] != '+' {
|
||||
if fi.zero && fi.width_set && fi.width > len(str) {
|
||||
strings.write_byte(fi.buf, str[0]);
|
||||
fmt_write_padding(fi, fi.width - len(str));
|
||||
strings.write_string(fi.buf, str[1:]);
|
||||
} else {
|
||||
_pad(fi, str);
|
||||
}
|
||||
} else {
|
||||
_pad(fi, str[1:]);
|
||||
}
|
||||
|
||||
case 'h', 'H':
|
||||
prev_fi := fi^;
|
||||
defer fi^ = prev_fi;
|
||||
fi.hash = false;
|
||||
fi.width = bit_size;
|
||||
fi.zero = true;
|
||||
fi.plus = false;
|
||||
|
||||
u: u64;
|
||||
switch bit_size {
|
||||
case 32: u = u64(transmute(u32)f32(v));
|
||||
case 64: u = transmute(u64)v;
|
||||
case: panic("Unhandled float size");
|
||||
}
|
||||
|
||||
strings.write_string(fi.buf, "0h");
|
||||
_fmt_int(fi, u, 16, false, bit_size, verb == 'h' ? __DIGITS_LOWER : __DIGITS_UPPER);
|
||||
|
||||
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
}
|
||||
@@ -623,13 +674,20 @@ fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) {
|
||||
}
|
||||
|
||||
fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
|
||||
u := u64(uintptr(p));
|
||||
switch verb {
|
||||
case 'p', 'v':
|
||||
u := u64(uintptr(p));
|
||||
if !fi.hash || verb == 'v' {
|
||||
strings.write_string(fi.buf, "0x");
|
||||
}
|
||||
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
|
||||
case 'b': _fmt_int(fi, u, 2, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
case 'o': _fmt_int(fi, u, 8, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
case 'd': _fmt_int(fi, u, 10, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
case 'x': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
case 'X': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
}
|
||||
@@ -982,6 +1040,43 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
if v.id == typeid_of(^runtime.Type_Info) {
|
||||
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
|
||||
} else {
|
||||
if verb != 'p' {
|
||||
ptr := (^rawptr)(v.data)^;
|
||||
a := any{ptr, info.elem.id};
|
||||
|
||||
elem := runtime.type_info_base(info.elem);
|
||||
if elem != nil do switch e in elem.variant {
|
||||
case runtime.Type_Info_Array,
|
||||
runtime.Type_Info_Slice,
|
||||
runtime.Type_Info_Dynamic_Array,
|
||||
runtime.Type_Info_Map:
|
||||
if ptr == nil {
|
||||
strings.write_string(fi.buf, "<nil>");
|
||||
return;
|
||||
}
|
||||
if fi.record_level < 1 {
|
||||
fi.record_level += 1;
|
||||
defer fi.record_level -= 1;
|
||||
strings.write_byte(fi.buf, '&');
|
||||
fmt_value(fi, a, verb);
|
||||
return;
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Struct,
|
||||
runtime.Type_Info_Union:
|
||||
if ptr == nil {
|
||||
strings.write_string(fi.buf, "<nil>");
|
||||
return;
|
||||
}
|
||||
if fi.record_level < 1 {
|
||||
fi.record_level += 1;
|
||||
defer fi.record_level -= 1;
|
||||
strings.write_byte(fi.buf, '&');
|
||||
fmt_value(fi, a, verb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt_pointer(fi, (^rawptr)(v.data)^, verb);
|
||||
}
|
||||
|
||||
@@ -996,14 +1091,19 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
strings.write_byte(fi.buf, '[');
|
||||
defer strings.write_byte(fi.buf, ']');
|
||||
array := cast(^mem.Raw_Dynamic_Array)v.data;
|
||||
for i in 0..array.len-1 {
|
||||
if i > 0 do strings.write_string(fi.buf, ", ");
|
||||
if verb == 'p' {
|
||||
slice := cast(^mem.Raw_Dynamic_Array)v.data;
|
||||
fmt_pointer(fi, slice.data, 'p');
|
||||
} else {
|
||||
strings.write_byte(fi.buf, '[');
|
||||
defer strings.write_byte(fi.buf, ']');
|
||||
array := cast(^mem.Raw_Dynamic_Array)v.data;
|
||||
for i in 0..array.len-1 {
|
||||
if i > 0 do strings.write_string(fi.buf, ", ");
|
||||
|
||||
data := uintptr(array.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
||||
data := uintptr(array.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
||||
}
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Simd_Vector:
|
||||
@@ -1021,16 +1121,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
strings.write_byte(fi.buf, '[');
|
||||
defer strings.write_byte(fi.buf, ']');
|
||||
slice := cast(^mem.Raw_Slice)v.data;
|
||||
for i in 0..slice.len-1 {
|
||||
if i > 0 do strings.write_string(fi.buf, ", ");
|
||||
if verb == 'p' {
|
||||
slice := cast(^mem.Raw_Slice)v.data;
|
||||
fmt_pointer(fi, slice.data, 'p');
|
||||
} else {
|
||||
strings.write_byte(fi.buf, '[');
|
||||
defer strings.write_byte(fi.buf, ']');
|
||||
slice := cast(^mem.Raw_Slice)v.data;
|
||||
for i in 0..slice.len-1 {
|
||||
if i > 0 do strings.write_string(fi.buf, ", ");
|
||||
|
||||
data := uintptr(slice.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
||||
data := uintptr(slice.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
||||
}
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Map:
|
||||
if verb != 'v' {
|
||||
fmt_bad_verb(fi, verb);
|
||||
@@ -1161,7 +1265,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
|
||||
fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
|
||||
switch verb {
|
||||
case 'f', 'F', 'v':
|
||||
case 'f', 'F', 'v', 'h', 'H':
|
||||
r, i := real(c), imag(c);
|
||||
fmt_float(fi, r, bits/2, verb);
|
||||
if !fi.plus && i >= 0 {
|
||||
|
||||
@@ -212,7 +212,7 @@ get_last_error :: proc() -> int {
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.new_cstring(path);
|
||||
cstr := strings.clone_to_cstring(path);
|
||||
handle := _unix_open(cstr, flags, mode);
|
||||
delete(cstr);
|
||||
if handle == -1 {
|
||||
@@ -289,7 +289,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
}
|
||||
|
||||
stat :: inline proc(path: string) -> (Stat, Errno) {
|
||||
cstr := strings.new_cstring(path);
|
||||
cstr := strings.clone_to_cstring(path);
|
||||
defer delete(cstr);
|
||||
|
||||
s: Stat;
|
||||
@@ -310,7 +310,7 @@ fstat :: inline proc(fd: Handle) -> (Stat, Errno) {
|
||||
}
|
||||
|
||||
access :: inline proc(path: string, mask: int) -> (bool, Errno) {
|
||||
cstr := strings.new_cstring(path);
|
||||
cstr := strings.clone_to_cstring(path);
|
||||
defer delete(cstr);
|
||||
result := _unix_access(cstr, mask);
|
||||
if result == -1 {
|
||||
@@ -333,7 +333,7 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_cstring(name);
|
||||
path_str := strings.clone_to_cstring(name);
|
||||
defer delete(path_str);
|
||||
cstr := _unix_getenv(path_str);
|
||||
if cstr == nil {
|
||||
@@ -370,14 +370,14 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.new_cstring(filename);
|
||||
cstr := strings.clone_to_cstring(filename);
|
||||
defer delete(cstr);
|
||||
handle := _unix_dlopen(cstr, flags);
|
||||
return handle;
|
||||
}
|
||||
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil);
|
||||
cstr := strings.new_cstring(symbol);
|
||||
cstr := strings.clone_to_cstring(symbol);
|
||||
defer delete(cstr);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
return proc_handle;
|
||||
|
||||
+75
-15
@@ -213,28 +213,28 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str
|
||||
|
||||
|
||||
|
||||
DecimalSlice :: struct {
|
||||
Decimal_Slice :: struct {
|
||||
digits: []byte,
|
||||
count: int,
|
||||
decimal_point: int,
|
||||
neg: bool,
|
||||
}
|
||||
|
||||
FloatInfo :: struct {
|
||||
Float_Info :: struct {
|
||||
mantbits: uint,
|
||||
expbits: uint,
|
||||
bias: int,
|
||||
}
|
||||
|
||||
|
||||
_f16_info := FloatInfo{10, 5, -15};
|
||||
_f32_info := FloatInfo{23, 8, -127};
|
||||
_f64_info := FloatInfo{52, 11, -1023};
|
||||
_f16_info := Float_Info{10, 5, -15};
|
||||
_f32_info := Float_Info{23, 8, -127};
|
||||
_f64_info := Float_Info{52, 11, -1023};
|
||||
|
||||
|
||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||
bits: u64;
|
||||
flt: ^FloatInfo;
|
||||
flt: ^Float_Info;
|
||||
switch bit_size {
|
||||
case 32:
|
||||
bits = u64(transmute(u32)f32(val));
|
||||
@@ -276,11 +276,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
d := &d_;
|
||||
assign(d, mant);
|
||||
shift(d, exp - int(flt.mantbits));
|
||||
digs: DecimalSlice;
|
||||
digs: Decimal_Slice;
|
||||
shortest := prec < 0;
|
||||
if shortest {
|
||||
round_shortest(d, mant, exp, flt);
|
||||
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||
switch fmt {
|
||||
case 'e', 'E': prec = digs.count-1;
|
||||
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
||||
@@ -297,14 +297,14 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
round(d, prec);
|
||||
}
|
||||
|
||||
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||
}
|
||||
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte {
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||
Buffer :: struct {
|
||||
b: []byte,
|
||||
n: int,
|
||||
@@ -347,12 +347,72 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
||||
return to_bytes(b);
|
||||
|
||||
case 'e', 'E':
|
||||
panic("strconv: e/E float printing is not yet supported");
|
||||
return to_bytes(b); // TODO
|
||||
add_bytes(&b, neg ? '-' : '+');
|
||||
|
||||
ch := byte('0');
|
||||
if digs.count != 0 {
|
||||
ch = digs.digits[0];
|
||||
}
|
||||
add_bytes(&b, ch);
|
||||
|
||||
if prec > 0 {
|
||||
add_bytes(&b, '.');
|
||||
i := 1;
|
||||
m := min(digs.count, prec+1);
|
||||
if i < m {
|
||||
add_bytes(&b, ..digs.digits[i:m]);
|
||||
i = m;
|
||||
}
|
||||
for ; i <= prec; i += 1 {
|
||||
add_bytes(&b, '0');
|
||||
}
|
||||
}
|
||||
|
||||
add_bytes(&b, fmt);
|
||||
exp := digs.decimal_point-1;
|
||||
if digs.count == 0 {
|
||||
// Zero has exponent of 0
|
||||
exp = 0;
|
||||
}
|
||||
|
||||
ch = '+';
|
||||
if exp < 0 {
|
||||
ch = '-';
|
||||
exp = -exp;
|
||||
}
|
||||
add_bytes(&b, ch);
|
||||
|
||||
switch {
|
||||
case exp < 10: add_bytes(&b, '0', byte(exp)+'0'); // add prefix 0
|
||||
case exp < 100: add_bytes(&b, byte(exp/10)+'0', byte(exp%10)+'0');
|
||||
case: add_bytes(&b, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0');
|
||||
}
|
||||
|
||||
return to_bytes(b);
|
||||
|
||||
case 'g', 'G':
|
||||
panic("strconv: g/G float printing is not yet supported");
|
||||
return to_bytes(b); // TODO
|
||||
eprec := prec;
|
||||
if eprec > digs.count && digs.count >= digs.decimal_point {
|
||||
eprec = digs.count;
|
||||
}
|
||||
|
||||
if shortest {
|
||||
eprec = 6;
|
||||
}
|
||||
|
||||
exp := digs.decimal_point - 1;
|
||||
if exp < -4 || exp >= eprec {
|
||||
if prec > digs.count {
|
||||
prec = digs.count;
|
||||
}
|
||||
return format_digits(buf, shortest, neg, digs, prec-1, fmt+'e'-'g'); // keep the same case
|
||||
}
|
||||
|
||||
if prec > digs.decimal_point {
|
||||
prec = digs.count;
|
||||
}
|
||||
|
||||
return format_digits(buf, shortest, neg, digs, max(prec-digs.decimal_point, 0), 'f');
|
||||
|
||||
case:
|
||||
add_bytes(&b, '%', fmt);
|
||||
@@ -362,7 +422,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
||||
|
||||
}
|
||||
|
||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
if mant == 0 { // If mantissa is zero, the number is zero
|
||||
d.count = 0;
|
||||
return;
|
||||
|
||||
@@ -17,6 +17,10 @@ destroy_builder :: proc(b: ^Builder) {
|
||||
clear(&b.buf);
|
||||
}
|
||||
|
||||
grow_builder :: proc(b: ^Builder, cap: int) {
|
||||
reserve(&b.buf, cap);
|
||||
}
|
||||
|
||||
builder_from_slice :: proc(backing: []byte) -> Builder {
|
||||
s := transmute(mem.Raw_Slice)backing;
|
||||
d := mem.Raw_Dynamic_Array{
|
||||
|
||||
+200
-1
@@ -3,6 +3,21 @@ package strings
|
||||
import "core:mem"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
clone :: proc(s: string, allocator := context.allocator) -> string {
|
||||
c := make([]byte, len(s)+1, allocator);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return string(c[:len(s)]);
|
||||
}
|
||||
|
||||
clone_to_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
|
||||
c := make([]byte, len(s)+1, allocator);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return cstring(&c[0]);
|
||||
}
|
||||
|
||||
@(deprecated="Please use 'strings.clone'")
|
||||
new_string :: proc(s: string, allocator := context.allocator) -> string {
|
||||
c := make([]byte, len(s)+1, allocator);
|
||||
copy(c, cast([]byte)s);
|
||||
@@ -10,6 +25,7 @@ new_string :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return string(c[:len(s)]);
|
||||
}
|
||||
|
||||
@(deprecated="Please use 'strings.clone_to_cstring'")
|
||||
new_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
|
||||
c := make([]byte, len(s)+1, allocator);
|
||||
copy(c, cast([]byte)s);
|
||||
@@ -46,6 +62,10 @@ contains_any :: proc(s, chars: string) -> bool {
|
||||
}
|
||||
|
||||
|
||||
rune_count :: proc(s: string) -> int {
|
||||
return utf8.rune_count_in_string(s);
|
||||
}
|
||||
|
||||
|
||||
equal_fold :: proc(s, t: string) -> bool {
|
||||
loop: for s != "" && t != "" {
|
||||
@@ -209,7 +229,7 @@ last_index_any :: proc(s, chars: string) -> int {
|
||||
|
||||
count :: proc(s, substr: string) -> int {
|
||||
if len(substr) == 0 { // special case
|
||||
return utf8.rune_count_in_string(s) + 1;
|
||||
return rune_count(s) + 1;
|
||||
}
|
||||
if len(substr) == 1 {
|
||||
c := substr[0];
|
||||
@@ -642,3 +662,182 @@ split_multi :: proc(s: string, substrs: []string, skip_empty := false, allocator
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
|
||||
// Adjacent invalid bytes are only replaced once
|
||||
scrub :: proc(str: string, replacement: string, allocator := context.allocator) -> string {
|
||||
b := make_builder(allocator);;
|
||||
grow_builder(&b, len(str));
|
||||
|
||||
has_error := false;
|
||||
cursor := 0;
|
||||
origin := str;
|
||||
|
||||
for len(str) > 0 {
|
||||
r, w := utf8.decode_rune_in_string(str);
|
||||
|
||||
if r == utf8.RUNE_ERROR {
|
||||
if !has_error {
|
||||
has_error = true;
|
||||
write_string(&b, origin[:cursor]);
|
||||
}
|
||||
} else if has_error {
|
||||
has_error = false;
|
||||
write_string(&b, replacement);
|
||||
|
||||
origin = origin[cursor:];
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
cursor += w;
|
||||
str = str[w:];
|
||||
}
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
reverse :: proc(str: string, allocator := context.allocator) -> string {
|
||||
n := len(str);
|
||||
buf := make([]byte, n);
|
||||
i := 0;
|
||||
|
||||
for len(str) > 0 {
|
||||
_, w := utf8.decode_rune_in_string(str);
|
||||
copy(buf[i:], cast([]byte)str[:w]);
|
||||
str = str[w:];
|
||||
}
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
expand_tabs :: proc(str: string, tab_size: int, allocator := context.allocator) -> string {
|
||||
if tab_size <= 0 {
|
||||
panic("tab size must be positive");
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
return "";
|
||||
}
|
||||
|
||||
b := make_builder(allocator);
|
||||
|
||||
column: int;
|
||||
|
||||
for len(str) > 0 {
|
||||
r, w := utf8.decode_rune_in_string(str);
|
||||
|
||||
if r == '\t' {
|
||||
expand := tab_size - column%tab_size;
|
||||
|
||||
for i := 0; i < expand; i += 1 {
|
||||
write_byte(&b, ' ');
|
||||
}
|
||||
|
||||
column += expand;
|
||||
} else {
|
||||
if r == '\n' {
|
||||
column = 0;
|
||||
} else {
|
||||
column += w;
|
||||
}
|
||||
|
||||
write_rune(&b, r);
|
||||
}
|
||||
|
||||
str = str[w:];
|
||||
}
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
partition :: proc(str, sep: string) -> (head, match, tail: string) {
|
||||
i := index(str, sep);
|
||||
if i == -1 {
|
||||
head = str;
|
||||
return;
|
||||
}
|
||||
|
||||
head = str[:i];
|
||||
match = str[i:i+len(sep)];
|
||||
tail = str[i+len(sep):];
|
||||
return;
|
||||
}
|
||||
|
||||
center_justify :: centre_justify; // NOTE(bill): Because Americans exist
|
||||
|
||||
// centre_justify returns a string with a pad string at boths sides if the str's rune length is smaller than length
|
||||
centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str);
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator);
|
||||
}
|
||||
|
||||
remains := length-1;
|
||||
pad_len := rune_count(pad);
|
||||
|
||||
b := make_builder(allocator);
|
||||
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
|
||||
|
||||
write_pad_string(&b, pad, pad_len, remains/2);
|
||||
write_string(&b, str);
|
||||
write_pad_string(&b, pad, pad_len, (remains+1)/2);
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length
|
||||
left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str);
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator);
|
||||
}
|
||||
|
||||
remains := length-1;
|
||||
pad_len := rune_count(pad);
|
||||
|
||||
b := make_builder(allocator);
|
||||
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
|
||||
|
||||
write_string(&b, str);
|
||||
write_pad_string(&b, pad, pad_len, remains);
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length
|
||||
right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str);
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator);
|
||||
}
|
||||
|
||||
remains := length-1;
|
||||
pad_len := rune_count(pad);
|
||||
|
||||
b := make_builder(allocator);
|
||||
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
|
||||
|
||||
write_pad_string(&b, pad, pad_len, remains);
|
||||
write_string(&b, str);
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
@private
|
||||
write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) {
|
||||
repeats := remains / pad_len;
|
||||
|
||||
for i := 0; i < repeats; i += 1 {
|
||||
write_string(b, pad);
|
||||
}
|
||||
|
||||
remains = remains % pad_len;
|
||||
|
||||
if remains != 0 do for i := 0; i < remains; i += 1 {
|
||||
r, w := utf8.decode_rune_in_string(pad);
|
||||
write_rune(b, r);
|
||||
pad = pad[w:];
|
||||
}
|
||||
}
|
||||
|
||||
+67
-79
@@ -11,92 +11,86 @@ Ordering :: enum {
|
||||
}
|
||||
|
||||
strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return Relaxed;
|
||||
case Release: return Relaxed;
|
||||
case Acquire: return Acquire;
|
||||
case Acquire_Release: return Acquire;
|
||||
case Sequentially_Consistent: return Sequentially_Consistent;
|
||||
case .Relaxed: return .Relaxed;
|
||||
case .Release: return .Relaxed;
|
||||
case .Acquire: return .Acquire;
|
||||
case .Acquire_Release: return .Acquire;
|
||||
case .Sequentially_Consistent: return .Sequentially_Consistent;
|
||||
}
|
||||
return Relaxed;
|
||||
return .Relaxed;
|
||||
}
|
||||
|
||||
fence :: inline proc "contextless" (order: Ordering) {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: panic("there is no such thing as a relaxed fence");
|
||||
case Release: intrinsics.atomic_fence_rel();
|
||||
case Acquire: intrinsics.atomic_fence_acq();
|
||||
case Acquire_Release: intrinsics.atomic_fence_acqrel();
|
||||
case Sequentially_Consistent: intrinsics.atomic_fence();
|
||||
case .Relaxed: panic("there is no such thing as a relaxed fence");
|
||||
case .Release: intrinsics.atomic_fence_rel();
|
||||
case .Acquire: intrinsics.atomic_fence_acq();
|
||||
case .Acquire_Release: intrinsics.atomic_fence_acqrel();
|
||||
case .Sequentially_Consistent: intrinsics.atomic_fence();
|
||||
case: panic("unknown order");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
atomic_store :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: intrinsics.atomic_store_relaxed(dst, val);
|
||||
case Release: intrinsics.atomic_store_rel(dst, val);
|
||||
case Sequentially_Consistent: intrinsics.atomic_store(dst, val);
|
||||
case Acquire: panic("there is not such thing as an acquire store");
|
||||
case Acquire_Release: panic("there is not such thing as an acquire/release store");
|
||||
case .Relaxed: intrinsics.atomic_store_relaxed(dst, val);
|
||||
case .Release: intrinsics.atomic_store_rel(dst, val);
|
||||
case .Sequentially_Consistent: intrinsics.atomic_store(dst, val);
|
||||
case .Acquire: panic("there is not such thing as an acquire store");
|
||||
case .Acquire_Release: panic("there is not such thing as an acquire/release store");
|
||||
case: panic("unknown order");
|
||||
}
|
||||
}
|
||||
|
||||
atomic_load :: inline proc "contextless" (dst: ^$T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_load_relaxed(dst);
|
||||
case Acquire: return intrinsics.atomic_load_acq(dst);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_load(dst);
|
||||
case Release: panic("there is no such thing as a release load");
|
||||
case Acquire_Release: panic("there is no such thing as an acquire/release load");
|
||||
case .Relaxed: return intrinsics.atomic_load_relaxed(dst);
|
||||
case .Acquire: return intrinsics.atomic_load_acq(dst);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_load(dst);
|
||||
case .Release: panic("there is no such thing as a release load");
|
||||
case .Acquire_Release: panic("there is no such thing as an acquire/release load");
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_swap :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_xchg_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_xchg_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_xchg_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_xchg_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, success, failure: Ordering) -> (val: T, ok: bool) {
|
||||
using Ordering;
|
||||
switch failure {
|
||||
case Relaxed:
|
||||
case .Relaxed:
|
||||
switch success {
|
||||
case Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new);
|
||||
case Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new);
|
||||
case Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new);
|
||||
case .Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new);
|
||||
case .Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new);
|
||||
case .Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new);
|
||||
case: panic("an unknown ordering combination");
|
||||
}
|
||||
case Acquire:
|
||||
case .Acquire:
|
||||
switch success {
|
||||
case Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new);
|
||||
case .Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new);
|
||||
case: panic("an unknown ordering combination");
|
||||
}
|
||||
case Sequentially_Consistent:
|
||||
case .Sequentially_Consistent:
|
||||
switch success {
|
||||
case Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new);
|
||||
case: panic("an unknown ordering combination");
|
||||
}
|
||||
case Acquire_Release:
|
||||
case .Acquire_Release:
|
||||
panic("there is not such thing as an acquire/release failure ordering");
|
||||
case Release:
|
||||
case .Release:
|
||||
panic("there is not such thing as an release failure ordering");
|
||||
}
|
||||
return T{}, false;
|
||||
@@ -105,78 +99,72 @@ atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, suc
|
||||
|
||||
|
||||
atomic_add :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_add_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_add_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_add_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_add(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_add_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_add_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_add_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_add(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_sub :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_sub_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_sub_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_sub_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_sub(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_sub_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_sub_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_sub_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_sub(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_and :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_and_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_and_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_and_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_and(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_and_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_and_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_and_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_and(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_nand :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_nand_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_nand_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_nand_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_nand(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_nand_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_nand_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_nand_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_nand(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_or :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_or_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_or_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_or_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_or(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_or_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_or_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_or_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_or(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
}
|
||||
|
||||
atomic_xor :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T {
|
||||
using Ordering;
|
||||
#complete switch order {
|
||||
case Relaxed: return intrinsics.atomic_xor_relaxed(dst, val);
|
||||
case Release: return intrinsics.atomic_xor_rel(dst, val);
|
||||
case Acquire: return intrinsics.atomic_xor_acq(dst, val);
|
||||
case Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val);
|
||||
case Sequentially_Consistent: return intrinsics.atomic_xor(dst, val);
|
||||
case .Relaxed: return intrinsics.atomic_xor_relaxed(dst, val);
|
||||
case .Release: return intrinsics.atomic_xor_rel(dst, val);
|
||||
case .Acquire: return intrinsics.atomic_xor_acq(dst, val);
|
||||
case .Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val);
|
||||
case .Sequentially_Consistent: return intrinsics.atomic_xor(dst, val);
|
||||
}
|
||||
panic("unknown order");
|
||||
return T{};
|
||||
|
||||
@@ -5,7 +5,6 @@ foreign import "system:kernel32.lib"
|
||||
|
||||
@(default_calling_convention = "std")
|
||||
foreign kernel32 {
|
||||
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
|
||||
@(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: cstring,
|
||||
process_attributes, thread_attributes: ^Security_Attributes,
|
||||
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
|
||||
@@ -18,8 +17,12 @@ foreign kernel32 {
|
||||
process_information: ^Process_Information) -> Bool ---;
|
||||
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
|
||||
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
|
||||
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hmodule ---;
|
||||
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hmodule ---;
|
||||
|
||||
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
|
||||
@(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
|
||||
|
||||
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
|
||||
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
|
||||
@@ -54,10 +57,6 @@ foreign kernel32 {
|
||||
@(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---;
|
||||
|
||||
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
|
||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
|
||||
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
|
||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
|
||||
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
|
||||
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
|
||||
|
||||
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
@@ -117,6 +116,17 @@ foreign kernel32 {
|
||||
@(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---;
|
||||
}
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
foreign kernel32 {
|
||||
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
|
||||
|
||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
|
||||
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
|
||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
|
||||
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
|
||||
@(link_name="CompareFileTime") compare_file_time :: proc(a, b: ^Filetime) -> i32 ---;
|
||||
}
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
foreign kernel32 {
|
||||
@(link_name="InterlockedCompareExchange") interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 ---;
|
||||
|
||||
Reference in New Issue
Block a user