mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-30 11:20:08 +00:00
++ -- statements; add strconv.odin (and replace some of the fmt procs); Fix ~ on 64 bit constants; Fix integer casts from smaller to larger size
This commit is contained in:
+3
-3
@@ -447,7 +447,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
||||
data := cast(^byte)array.data;
|
||||
assert(data != nil);
|
||||
mem.zero(data + (elem_size*array.count), elem_size);
|
||||
array.count += 1;
|
||||
array.count++;
|
||||
return array.count;
|
||||
}
|
||||
|
||||
@@ -506,7 +506,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
|
||||
nm.hashes[i] = -1;
|
||||
}
|
||||
|
||||
for i := 0; i < nm.entries.count; i += 1 {
|
||||
for i := 0; i < nm.entries.count; i++ {
|
||||
entry_header := __dynamic_map_get_entry(new_header, i);
|
||||
data := cast(^byte)entry_header;
|
||||
|
||||
@@ -645,7 +645,7 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
||||
}
|
||||
|
||||
if fr.entry_index == m.entries.count-1 {
|
||||
m.entries.count -= 1;
|
||||
m.entries.count--;
|
||||
}
|
||||
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
||||
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
counter++;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
@@ -81,7 +81,7 @@ spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
counter++;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
// #import "fmt.odin";
|
||||
// Multiple precision decimal numbers
|
||||
// NOTE: This is only for floating point printing and nothing else
|
||||
|
||||
Decimal :: struct {
|
||||
d: [384]byte, // big-endian digits
|
||||
ndu: int,
|
||||
dp: int,
|
||||
neg: bool,
|
||||
trunc: bool,
|
||||
}
|
||||
|
||||
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||
digit_zero :: proc(buf: []byte) -> int {
|
||||
for _, i in buf {
|
||||
buf[i] = '0';
|
||||
}
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
|
||||
n := 10 + a.ndu + abs(a.dp);
|
||||
|
||||
// TODO(bill): make this work with a buffer that's not big enough
|
||||
assert(buf.count >= n);
|
||||
buf = buf[:n];
|
||||
|
||||
if a.ndu == 0 {
|
||||
buf[0] = '0';
|
||||
return cast(string)buf[0:1];
|
||||
}
|
||||
|
||||
w := 0;
|
||||
if a.dp <= 0 {
|
||||
buf[w] = '0'; w++;
|
||||
buf[w] = '.'; w++;
|
||||
w += digit_zero(buf[w: w-a.dp]);
|
||||
w += copy(buf[w:], a.d[0:a.ndu]);
|
||||
} else if a.dp < a.ndu {
|
||||
w += copy(buf[w:], a.d[0:a.dp]);
|
||||
buf[w] = '.'; w++;
|
||||
w += copy(buf[w:], a.d[a.dp:a.ndu]);
|
||||
} else {
|
||||
w += copy(buf[w:], a.d[0:a.ndu]);
|
||||
w += digit_zero(buf[w : w+a.dp-a.ndu]);
|
||||
}
|
||||
|
||||
return cast(string)buf[0:w];
|
||||
}
|
||||
|
||||
// trim trailing zeros
|
||||
trim :: proc(a: ^Decimal) {
|
||||
for a.ndu > 0 && a.d[a.ndu-1] == '0' {
|
||||
a.ndu--;
|
||||
}
|
||||
if a.ndu == 0 {
|
||||
a.dp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assign :: proc(a: ^Decimal, i: u64) {
|
||||
buf: [32]byte;
|
||||
n := 0;
|
||||
for i > 0 {
|
||||
j := i/10;
|
||||
i -= 10*j;
|
||||
buf[n] = cast(byte)('0'+i);
|
||||
n++;
|
||||
i = j;
|
||||
}
|
||||
|
||||
a.ndu = 0;
|
||||
for n--; n >= 0; n-- {
|
||||
a.d[a.ndu] = buf[n];
|
||||
a.ndu++;
|
||||
}
|
||||
a.dp = a.ndu;
|
||||
trim(a);
|
||||
}
|
||||
|
||||
uint_size :: 8*size_of(uint);
|
||||
max_shift :: uint_size-4;
|
||||
|
||||
shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
r := 0; // read index
|
||||
w := 0; // write index
|
||||
|
||||
n: uint;
|
||||
for ; n>>k == 0; r++ {
|
||||
if r >= a.ndu {
|
||||
if n == 0 {
|
||||
// Just in case
|
||||
a.ndu = 0;
|
||||
return;
|
||||
}
|
||||
for n>>k == 0 {
|
||||
n = n * 10;
|
||||
r++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
c := cast(uint)a.d[r];
|
||||
n = n*10 + c - '0';
|
||||
}
|
||||
a.dp -= r-1;
|
||||
|
||||
mask: uint = (1<<k) - 1;
|
||||
|
||||
for ; r < a.ndu; r++ {
|
||||
c := cast(uint)a.d[r];
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
a.d[w] = cast(byte)('0' + dig);
|
||||
w++;
|
||||
n = n*10 + c - '0';
|
||||
}
|
||||
|
||||
for n > 0 {
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
if w < a.d.count {
|
||||
a.d[w] = cast(byte)('0' + dig);
|
||||
w++;
|
||||
} else if dig > 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
n *= 10;
|
||||
}
|
||||
|
||||
|
||||
a.ndu = w;
|
||||
trim(a);
|
||||
}
|
||||
|
||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
delta := cast(int)(k/4);
|
||||
|
||||
r := a.ndu; // read index
|
||||
w := a.ndu+delta; // write index
|
||||
|
||||
n: uint;
|
||||
for r--; r >= 0; r-- {
|
||||
n += (cast(uint)a.d[r] - '0') << k;
|
||||
quo := n/10;
|
||||
rem := n - 10*quo;
|
||||
w--;
|
||||
if w < a.d.count {
|
||||
a.d[w] = cast(byte)('0' + rem);
|
||||
} else if rem != 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
n = quo;
|
||||
}
|
||||
|
||||
for n > 0 {
|
||||
quo := n/10;
|
||||
rem := n - 10*quo;
|
||||
w--;
|
||||
if w < a.d.count {
|
||||
a.d[w] = cast(byte)('0' + rem);
|
||||
} else if rem != 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
n = quo;
|
||||
}
|
||||
|
||||
a.ndu += delta;
|
||||
a.ndu = min(a.ndu, a.d.count);
|
||||
a.dp += delta;
|
||||
trim(a);
|
||||
}
|
||||
|
||||
shift :: proc(a: ^Decimal, k: int) {
|
||||
match {
|
||||
case a.ndu == 0:
|
||||
// no need to update
|
||||
case k > 0:
|
||||
for k > max_shift {
|
||||
shift_left(a, max_shift);
|
||||
k -= max_shift;
|
||||
}
|
||||
shift_left(a, cast(uint)k);
|
||||
|
||||
|
||||
case k < 0:
|
||||
for k < -max_shift {
|
||||
shift_right(a, max_shift);
|
||||
k += max_shift;
|
||||
}
|
||||
shift_right(a, cast(uint)-k);
|
||||
}
|
||||
}
|
||||
|
||||
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
|
||||
if nd < 0 || nd >= a.ndu { return false ; }
|
||||
if a.d[nd] == '5' && nd+1 == a.ndu {
|
||||
if a.trunc {
|
||||
return true;
|
||||
}
|
||||
return nd > 0 && (a.d[nd-1]-'0')%2 != 0;
|
||||
}
|
||||
|
||||
return a.d[nd] >= '5';
|
||||
}
|
||||
|
||||
round :: proc(a: ^Decimal, nd: int) {
|
||||
if nd < 0 || nd >= a.ndu { return; }
|
||||
if can_round_up(a, nd) {
|
||||
round_up(a, nd);
|
||||
} else {
|
||||
round_down(a, nd);
|
||||
}
|
||||
}
|
||||
|
||||
round_up :: proc(a: ^Decimal, nd: int) {
|
||||
if nd < 0 || nd >= a.ndu { return; }
|
||||
|
||||
for i := nd-1; i >= 0; i-- {
|
||||
if c := a.d[i]; c < '9' {
|
||||
a.d[i]++;
|
||||
a.ndu = i+1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Number is just 9s
|
||||
a.d[0] = '1';
|
||||
a.ndu = 1;
|
||||
a.dp++;
|
||||
}
|
||||
|
||||
round_down :: proc(a: ^Decimal, nd: int) {
|
||||
if nd < 0 || nd >= a.ndu { return; }
|
||||
a.ndu = nd;
|
||||
trim(a);
|
||||
}
|
||||
|
||||
|
||||
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
|
||||
rounded_integer :: proc(a: ^Decimal) -> u64 {
|
||||
if a.dp > 20 {
|
||||
return 0xffff_ffff_ffff_ffff;
|
||||
}
|
||||
i: int;
|
||||
n: u64 = 0;
|
||||
m := min(a.dp, a.ndu);
|
||||
for i = 0; i < m; i++ {
|
||||
n = n*10 + cast(u64)(a.d[i]-'0');
|
||||
}
|
||||
for ; i < a.dp; i++ {
|
||||
n *= 10;
|
||||
}
|
||||
if can_round_up(a, a.dp) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
+88
-126
@@ -2,6 +2,7 @@
|
||||
#import "mem.odin";
|
||||
#import "utf8.odin";
|
||||
#import "types.odin";
|
||||
#import "strconv.odin";
|
||||
|
||||
|
||||
_BUFFER_SIZE :: 1<<12;
|
||||
@@ -26,7 +27,7 @@ buffer_write_string :: proc(buf: ^Buffer, s: string) {
|
||||
buffer_write_byte :: proc(buf: ^Buffer, b: byte) {
|
||||
if buf.length < buf.data.count {
|
||||
buf.data[buf.length] = b;
|
||||
buf.length += 1;
|
||||
buf.length++;
|
||||
}
|
||||
}
|
||||
buffer_write_rune :: proc(buf: ^Buffer, r: rune) {
|
||||
@@ -226,7 +227,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
||||
buffer_write_string(buf, name);
|
||||
buffer_write_string(buf, ": ");
|
||||
buffer_write_type(buf, cf.types[i]);
|
||||
total_count += 1;
|
||||
total_count++;
|
||||
}
|
||||
for name, i in info.variant_names {
|
||||
if total_count > 0 || i > 0 {
|
||||
@@ -345,7 +346,7 @@ parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool
|
||||
if !is_digit(c) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
i++;
|
||||
|
||||
result *= 10;
|
||||
result += cast(int)(c - '0');
|
||||
@@ -459,17 +460,16 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
|
||||
fi.buf.length += count;
|
||||
}
|
||||
|
||||
fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
|
||||
negative := signed && cast(i64)u < 0;
|
||||
if signed {
|
||||
u = cast(u64)abs(cast(i64)u);
|
||||
_write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string) {
|
||||
if neg {
|
||||
u = -u;
|
||||
}
|
||||
buf: [256]byte;
|
||||
BUF_SIZE :: 256;
|
||||
if fi.width_set || fi.prec_set {
|
||||
width := fi.width + fi.prec + 3;
|
||||
if width > buf.count {
|
||||
if width > BUF_SIZE {
|
||||
// TODO(bill):????
|
||||
panic("fmt_integer buffer overrun. Width and precision too big");
|
||||
panic("_write_int buffer overrun. Width and precision too big");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,95 +485,64 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri
|
||||
}
|
||||
} else if fi.zero && fi.width_set {
|
||||
prec = fi.width;
|
||||
if negative || fi.plus || fi.space {
|
||||
if neg || fi.plus || fi.space {
|
||||
// There needs to be space for the "sign"
|
||||
prec -= 1;
|
||||
prec--;
|
||||
}
|
||||
}
|
||||
|
||||
i := buf.count;
|
||||
|
||||
match base {
|
||||
case 2, 8, 10, 16:
|
||||
break;
|
||||
default:
|
||||
panic("fmt_integer: unknown base, whoops");
|
||||
panic("_write_int: unknown base, whoops");
|
||||
}
|
||||
|
||||
for b := cast(u64)base; u >= b; {
|
||||
i -= 1;
|
||||
next := u / b;
|
||||
buf[i] = digits[u%b];
|
||||
u = next;
|
||||
}
|
||||
i -= 1;
|
||||
buf[i] = digits[u];
|
||||
for i > 0 && prec > buf.count-i {
|
||||
i -= 1;
|
||||
buf[i] = '0';
|
||||
}
|
||||
|
||||
if fi.hash {
|
||||
i -= 1;
|
||||
match base {
|
||||
case 2: buf[i] = 'b';
|
||||
case 8: buf[i] = 'o';
|
||||
case 10: buf[i] = 'd';
|
||||
case 16: buf[i] = digits[16];
|
||||
}
|
||||
i -= 1;
|
||||
buf[i] = '0';
|
||||
}
|
||||
|
||||
if negative {
|
||||
i -= 1;
|
||||
buf[i] = '-';
|
||||
} else if fi.plus {
|
||||
i -= 1;
|
||||
buf[i] = '+';
|
||||
} else if fi.space {
|
||||
i -= 1;
|
||||
buf[i] = ' ';
|
||||
}
|
||||
buf: [256]byte;
|
||||
flags: strconv.Int_Flag;
|
||||
if fi.hash { flags |= strconv.Int_Flag.PREFIX; }
|
||||
if fi.plus { flags |= strconv.Int_Flag.PLUS; }
|
||||
if fi.space { flags |= strconv.Int_Flag.SPACE; }
|
||||
s := strconv.format_bits(buf[:], u, base, neg, digits, flags);
|
||||
|
||||
old_zero := fi.zero;
|
||||
defer fi.zero = old_zero;
|
||||
fi.zero = false;
|
||||
|
||||
if !fi.width_set || fi.width == 0 {
|
||||
buffer_write(fi.buf, buf[i:]);
|
||||
buffer_write_string(fi.buf, s);
|
||||
} else {
|
||||
width := fi.width - utf8.rune_count(cast(string)buf[i:]);
|
||||
width := fi.width - utf8.rune_count(s);
|
||||
if width > 0 {
|
||||
if fi.minus {
|
||||
// Right pad
|
||||
buffer_write(fi.buf, buf[i:]);
|
||||
buffer_write_string(fi.buf, s);
|
||||
fmt_write_padding(fi, width);
|
||||
} else {
|
||||
// Left pad
|
||||
fmt_write_padding(fi, width);
|
||||
buffer_write(fi.buf, buf[i:]);
|
||||
buffer_write_string(fi.buf, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
__DIGITS_LOWER := "0123456789abcdefx";
|
||||
__DIGITS_UPPER := "0123456789ABCDEFX";
|
||||
immutable __DIGITS_LOWER := "0123456789abcdefx";
|
||||
immutable __DIGITS_UPPER := "0123456789ABCDEFX";
|
||||
|
||||
fmt_rune :: proc(fi: ^Fmt_Info, r: rune) {
|
||||
buffer_write_rune(fi.buf, r);
|
||||
}
|
||||
|
||||
fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) {
|
||||
fmt_int :: proc(fi: ^Fmt_Info, u: u64, neg: bool, verb: rune) {
|
||||
match verb {
|
||||
case 'v': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER);
|
||||
case 'b': fmt_integer(fi, u, 2, signed, __DIGITS_LOWER);
|
||||
case 'o': fmt_integer(fi, u, 8, signed, __DIGITS_LOWER);
|
||||
case 'd': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER);
|
||||
case 'x': fmt_integer(fi, u, 16, signed, __DIGITS_LOWER);
|
||||
case 'X': fmt_integer(fi, u, 16, signed, __DIGITS_UPPER);
|
||||
case 'v': _write_int(fi, u, 10, neg, __DIGITS_LOWER);
|
||||
case 'b': _write_int(fi, u, 2, neg, __DIGITS_LOWER);
|
||||
case 'o': _write_int(fi, u, 8, neg, __DIGITS_LOWER);
|
||||
case 'd': _write_int(fi, u, 10, neg, __DIGITS_LOWER);
|
||||
case 'x': _write_int(fi, u, 16, neg, __DIGITS_LOWER);
|
||||
case 'X': _write_int(fi, u, 16, neg, __DIGITS_UPPER);
|
||||
case 'c', 'r':
|
||||
fmt_rune(fi, cast(rune)u);
|
||||
case 'U':
|
||||
@@ -582,7 +551,7 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) {
|
||||
fmt_bad_verb(fi, verb);
|
||||
} else {
|
||||
buffer_write_string(fi.buf, "U+");
|
||||
fmt_integer(fi, u, 16, false, __DIGITS_UPPER);
|
||||
_write_int(fi, u, 16, false, __DIGITS_UPPER);
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -592,67 +561,60 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) {
|
||||
|
||||
|
||||
fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
||||
pad :: proc(fi: ^Fmt_Info, s: string) {
|
||||
if !fi.width_set || fi.width == 0 {
|
||||
buffer_write_string(fi.buf, s);
|
||||
return;
|
||||
}
|
||||
width := fi.width - utf8.rune_count(s);
|
||||
if fi.minus { // right pad
|
||||
buffer_write_string(fi.buf, s);
|
||||
fmt_write_padding(fi, width);
|
||||
} else { // left pad
|
||||
fmt_write_padding(fi, width);
|
||||
buffer_write_string(fi.buf, s);
|
||||
}
|
||||
}
|
||||
|
||||
match verb {
|
||||
// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
|
||||
// case 'f', 'F', 'v':
|
||||
|
||||
// TODO(bill): This is a shit copy from gb.h and I really need a decent implementation
|
||||
case 'f', 'F', 'v':
|
||||
width := 0;
|
||||
if fi.width_set {
|
||||
width = max(fi.width, 0);
|
||||
}
|
||||
prec := 3;
|
||||
prec: int = 3;
|
||||
if fi.prec_set {
|
||||
prec = max(fi.prec, 0);
|
||||
prec = fi.prec;
|
||||
}
|
||||
buf: [128]byte;
|
||||
str := strconv.format_float(buf[1:], v, 'f', prec, bit_size);
|
||||
str = cast(string)buf[:str.count+1];
|
||||
if str[1] == '+' || str[1] == '-' {
|
||||
str = str[1:];
|
||||
} else {
|
||||
str[0] = '+';
|
||||
}
|
||||
|
||||
if v == 0 {
|
||||
buffer_write_byte(fi.buf, '0');
|
||||
if fi.hash && width > 0 {
|
||||
buffer_write_byte(fi.buf, '.');
|
||||
if fi.space && !fi.plus && str[0] == '+' {
|
||||
str[0] = ' ';
|
||||
}
|
||||
|
||||
if str[1] == 'N' && str[1] == 'I' {
|
||||
buffer_write_string(fi.buf, str);
|
||||
return;
|
||||
}
|
||||
|
||||
if fi.plus || str[0] != '+' {
|
||||
if fi.zero && fi.width_set && fi.width > str.count {
|
||||
buffer_write_byte(fi.buf, str[0]);
|
||||
fmt_write_padding(fi, fi.width - str.count);
|
||||
buffer_write_string(fi.buf, str[1:]);
|
||||
} else {
|
||||
pad(fi, str);
|
||||
}
|
||||
} else {
|
||||
signed := v < 0;
|
||||
v = abs(v);
|
||||
|
||||
if signed {
|
||||
buffer_write_byte(fi.buf, '-');
|
||||
}
|
||||
|
||||
val := cast(u64)v;
|
||||
fi.minus = false;
|
||||
fi.width = 0;
|
||||
fi.prec = 0;
|
||||
// TODO(bill): Write integer to buffer than use this crap
|
||||
fmt_integer(fi, val, 10, false, __DIGITS_LOWER);
|
||||
|
||||
if fi.hash || prec > 0 {
|
||||
arg := v - cast(f64)val;
|
||||
mult: f64 = 10;
|
||||
buffer_write_byte(fi.buf, '.');
|
||||
for _ in 0..<prec {
|
||||
val := cast(u64)(arg*mult);
|
||||
buffer_write_byte(fi.buf, __DIGITS_LOWER[cast(u64)val]);
|
||||
arg -= cast(f64)val / mult;
|
||||
mult *= 10;
|
||||
}
|
||||
}
|
||||
pad(fi, str[1:]);
|
||||
}
|
||||
|
||||
|
||||
if width > 0 {
|
||||
fill: byte = ' ';
|
||||
match {
|
||||
case fi.zero: fill = '0';
|
||||
case fi.space: fill = ' ';
|
||||
}
|
||||
|
||||
for width > 0 {
|
||||
width -= 1;
|
||||
buffer_write_byte(fi.buf, fill);
|
||||
}
|
||||
}
|
||||
default:
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
@@ -679,7 +641,7 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
||||
if !fi.hash || verb == 'v' {
|
||||
buffer_write_string(fi.buf, "0x");
|
||||
}
|
||||
fmt_integer(fi, u, 16, false, __DIGITS_UPPER);
|
||||
_write_int(fi, u, 16, false, __DIGITS_UPPER);
|
||||
}
|
||||
|
||||
fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
@@ -957,11 +919,11 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
case f32: fmt_float(fi, cast(f64)a, 32, verb);
|
||||
case f64: fmt_float(fi, a, 64, verb);
|
||||
|
||||
case int: fmt_int(fi, cast(u64)a, true, verb);
|
||||
case i8: fmt_int(fi, cast(u64)a, true, verb);
|
||||
case i16: fmt_int(fi, cast(u64)a, true, verb);
|
||||
case i32: fmt_int(fi, cast(u64)a, true, verb);
|
||||
case i64: fmt_int(fi, cast(u64)a, true, verb);
|
||||
case int: fmt_int(fi, cast(u64)a, a < 0, verb);
|
||||
case i8: fmt_int(fi, cast(u64)a, a < 0, verb);
|
||||
case i16: fmt_int(fi, cast(u64)a, a < 0, verb);
|
||||
case i32: fmt_int(fi, cast(u64)a, a < 0, verb);
|
||||
case i64: fmt_int(fi, cast(u64)a, a < 0, verb);
|
||||
case uint: fmt_int(fi, cast(u64)a, false, verb);
|
||||
case u8: fmt_int(fi, cast(u64)a, false, verb);
|
||||
case u16: fmt_int(fi, cast(u64)a, false, verb);
|
||||
@@ -984,7 +946,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
||||
|
||||
prev_i := i;
|
||||
for i < end && fmt[i] != '%' {
|
||||
i += 1;
|
||||
i++;
|
||||
}
|
||||
if i > prev_i {
|
||||
buffer_write_string(b, fmt[prev_i:i]);
|
||||
@@ -994,10 +956,10 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
||||
}
|
||||
|
||||
// Process a "verb"
|
||||
i += 1;
|
||||
i++;
|
||||
|
||||
|
||||
for ; i < end; i += 1 {
|
||||
for ; i < end; i++ {
|
||||
skip_loop := false;
|
||||
c := fmt[i];
|
||||
match c {
|
||||
@@ -1025,7 +987,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
||||
|
||||
// Width
|
||||
if i < end && fmt[i] == '*' {
|
||||
i += 1;
|
||||
i++;
|
||||
fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index);
|
||||
if !fi.width_set {
|
||||
buffer_write_string(b, "%!(BAD WIDTH)");
|
||||
@@ -1046,13 +1008,13 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
||||
|
||||
// Precision
|
||||
if i < end && fmt[i] == '.' {
|
||||
i += 1;
|
||||
i++;
|
||||
if was_prev_index { // %[6].2d
|
||||
fi.good_arg_index = false;
|
||||
}
|
||||
if i < end && fmt[i] == '*' {
|
||||
arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count);
|
||||
i += 1;
|
||||
i++;
|
||||
fi.prec, arg_index, fi.prec_set = int_from_arg(args, arg_index);
|
||||
if fi.prec < 0 {
|
||||
fi.prec = 0;
|
||||
@@ -1091,7 +1053,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
||||
buffer_write_string(b, "%!(MISSING ARGUMENT)");
|
||||
} else {
|
||||
fmt_arg(^fi, args[arg_index], verb);
|
||||
arg_index += 1;
|
||||
arg_index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -146,7 +146,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
i := 0;
|
||||
for len >= 8 {
|
||||
k1, k2: u32;
|
||||
k1 = data32[i]; i += 1;
|
||||
k1 = data32[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -154,7 +154,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
h1 ~= k1;
|
||||
len -= 4;
|
||||
|
||||
k2 = data32[i]; i += 1;
|
||||
k2 = data32[i]; i++;
|
||||
k2 *= m;
|
||||
k2 ~= k2>>r;
|
||||
k2 *= m;
|
||||
@@ -165,7 +165,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
|
||||
if len >= 4 {
|
||||
k1: u32;
|
||||
k1 = data32[i]; i += 1;
|
||||
k1 = data32[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
|
||||
+3
-3
@@ -79,7 +79,7 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
|
||||
header.size = size;
|
||||
ptr := cast(^int)(header+1);
|
||||
|
||||
for i := 0; cast(rawptr)ptr < data; i += 1 {
|
||||
for i := 0; cast(rawptr)ptr < data; i++ {
|
||||
(ptr+i)^ = -1;
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
|
||||
tmp: Arena_Temp_Memory;
|
||||
tmp.arena = a;
|
||||
tmp.original_count = a.memory.count;
|
||||
a.temp_count += 1;
|
||||
a.temp_count++;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
|
||||
assert(arena.memory.count >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
arena.memory.count = original_count;
|
||||
arena.temp_count -= 1;
|
||||
arena.temp_count--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
#import . "decimal.odin";
|
||||
#import "math.odin";
|
||||
#import format "fmt.odin";
|
||||
|
||||
Int_Flag :: enum {
|
||||
PREFIX = 1<<0,
|
||||
PLUS = 1<<1,
|
||||
SPACE = 1<<2,
|
||||
}
|
||||
|
||||
|
||||
parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
||||
match s {
|
||||
case "1", "t", "T", "true", "TRUE", "True":
|
||||
return true, true;
|
||||
case "0", "f", "F", "false", "FALSE", "False":
|
||||
return false, true;
|
||||
}
|
||||
return false, false;
|
||||
}
|
||||
|
||||
format_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
s := b ? "true" : "false";
|
||||
len := copy(buf, cast([]byte)s);
|
||||
return cast(string)buf[:len];
|
||||
}
|
||||
|
||||
format_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
using Int_Flag;
|
||||
return format_bits(buf, u, base, false, digits, 0);
|
||||
}
|
||||
format_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return format_bits(buf, cast(u64)i, base, i < 0, digits, 0);
|
||||
}
|
||||
itoa :: proc(buf: []byte, i: int) -> string {
|
||||
return format_int(buf, cast(i64)i, 10);
|
||||
}
|
||||
|
||||
format_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Decimal_Slice :: struct {
|
||||
d: []byte,
|
||||
ndu: int,
|
||||
dp: int,
|
||||
neg: bool,
|
||||
}
|
||||
|
||||
Float_Info :: struct {
|
||||
mantbits: uint,
|
||||
expbits: uint,
|
||||
bias: int,
|
||||
}
|
||||
|
||||
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: ^Float_Info;
|
||||
match bit_size {
|
||||
case 32:
|
||||
bits = cast(u64)transmute(u32)cast(f32)val;
|
||||
flt = ^f32_info;
|
||||
case 64:
|
||||
bits = transmute(u64)val;
|
||||
flt = ^f64_info;
|
||||
default:
|
||||
panic("strconv: invalid bit_size");
|
||||
}
|
||||
|
||||
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
||||
exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||
mant := bits & (cast(u64)1 << flt.mantbits - 1);
|
||||
|
||||
match exp {
|
||||
case 1<<flt.expbits - 1:
|
||||
s: string;
|
||||
if mant != 0 {
|
||||
s = "NaN";
|
||||
} else if neg {
|
||||
s = "-Inf";
|
||||
} else {
|
||||
s = "+Inf";
|
||||
}
|
||||
len := copy(buf, cast([]byte)s);
|
||||
return buf[:len];
|
||||
|
||||
case 0: // denormalized
|
||||
exp++;
|
||||
|
||||
default:
|
||||
mant |= cast(u64)1 << flt.mantbits;
|
||||
}
|
||||
|
||||
exp += flt.bias;
|
||||
|
||||
d_: Decimal;
|
||||
d := ^d_;
|
||||
assign(d, mant);
|
||||
shift(d, exp - cast(int)flt.mantbits);
|
||||
digs: Decimal_Slice;
|
||||
shortest := prec < 0;
|
||||
if shortest {
|
||||
round_shortest(d, mant, exp, flt);
|
||||
digs = Decimal_Slice{d = d.d[:], ndu = d.ndu, dp = d.dp};
|
||||
match fmt {
|
||||
case 'e', 'E':
|
||||
prec = digs.ndu-1;
|
||||
case 'f', 'F':
|
||||
prec = max(digs.ndu-digs.dp, 0);
|
||||
case 'g', 'G':
|
||||
prec = digs.ndu;
|
||||
}
|
||||
} else {
|
||||
match fmt {
|
||||
case 'e', 'E': round(d, prec+1);
|
||||
case 'f', 'F': round(d, d.dp+prec);
|
||||
case 'g', 'G':
|
||||
if prec == 0 {
|
||||
prec = 1;
|
||||
}
|
||||
round(d, prec);
|
||||
}
|
||||
|
||||
digs = Decimal_Slice{d = d.d[:], ndu = d.ndu, dp = d.dp};
|
||||
}
|
||||
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||
match fmt {
|
||||
case 'f', 'F':
|
||||
add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ...byte) {
|
||||
for b in bytes {
|
||||
if dst.count <= w^ {
|
||||
break;
|
||||
}
|
||||
dst[w^] = b;
|
||||
w^++;
|
||||
}
|
||||
}
|
||||
|
||||
dst := buf[:];
|
||||
w := 0;
|
||||
if neg {
|
||||
add_bytes(^dst, ^w, '-');
|
||||
} else {
|
||||
add_bytes(^dst, ^w, '+');
|
||||
}
|
||||
|
||||
// integer, padded with zeros when needed
|
||||
if digs.dp > 0 {
|
||||
m := min(digs.ndu, digs.dp);
|
||||
add_bytes(^dst, ^w, ...digs.d[:m]);
|
||||
for ; m < digs.dp; m++ {
|
||||
add_bytes(^dst, ^w, '0');
|
||||
}
|
||||
} else {
|
||||
add_bytes(^dst, ^w, '0');
|
||||
}
|
||||
|
||||
// fractional part
|
||||
if prec > 0 {
|
||||
add_bytes(^dst, ^w, '.');
|
||||
for i in 0..<prec {
|
||||
c: byte = '0';
|
||||
if j := digs.dp + i; 0 <= j && j < digs.ndu {
|
||||
c = digs.d[j];
|
||||
}
|
||||
add_bytes(^dst, ^w, c);
|
||||
}
|
||||
}
|
||||
|
||||
return buf[:w];
|
||||
|
||||
case 'e', 'E':
|
||||
return nil; // TODO
|
||||
|
||||
case 'g', 'G':
|
||||
return nil; // TODO
|
||||
}
|
||||
|
||||
c: [2]byte;
|
||||
c[0] = '%';
|
||||
c[1] = fmt;
|
||||
len := copy(buf, ...c[:]);
|
||||
return buf[:len];
|
||||
}
|
||||
|
||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
if mant == 0 { // If mantissa is zero, the number is zero
|
||||
d.ndu = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
10^(dp-nd) > 2^(exp-mantbits)
|
||||
log2(10) * (dp-nd) > exp-mantbits
|
||||
log(2) >~ 0.332
|
||||
332*(dp-nd) >= 100*(exp-mantbits)
|
||||
*/
|
||||
minexp := flt.bias+1;
|
||||
if exp > minexp && 332*(d.dp-d.ndu) >= 100*(exp - cast(int)flt.mantbits) {
|
||||
// Number is already its shortest
|
||||
return;
|
||||
}
|
||||
|
||||
upper_: Decimal; upper: = ^upper_;
|
||||
assign(upper, 2*mant - 1);
|
||||
shift(upper, exp - cast(int)flt.mantbits - 1);
|
||||
|
||||
mantlo: u64;
|
||||
explo: int;
|
||||
if mant > 1<<flt.mantbits || exp == minexp {
|
||||
mantlo = mant-1;
|
||||
explo = exp;
|
||||
} else {
|
||||
mantlo = 2*mant - 1;
|
||||
explo = exp-1;
|
||||
}
|
||||
lower_: Decimal; lower: = ^lower_;
|
||||
assign(lower, 2*mantlo + 1);
|
||||
shift(lower, explo - cast(int)flt.mantbits - 1);
|
||||
|
||||
inclusive := mant%2 == 0;
|
||||
|
||||
for i in 0..<d.ndu {
|
||||
l: byte = '0'; // lower digit
|
||||
if i < lower.ndu {
|
||||
l = lower.d[i];
|
||||
}
|
||||
m := d.d[i]; // middle digit
|
||||
u: byte = '0'; // upper digit
|
||||
if i < upper.ndu {
|
||||
u = upper.d[i];
|
||||
}
|
||||
|
||||
ok_round_down := l != m || inclusive && i+1 == lower.ndu;
|
||||
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.ndu);
|
||||
|
||||
if (ok_round_down && ok_round_up) {
|
||||
round(d, i+1);
|
||||
return;
|
||||
}
|
||||
if (ok_round_down) {
|
||||
round_down(d, i+1);
|
||||
return;
|
||||
}
|
||||
if (ok_round_up) {
|
||||
round_up(d, i+1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MAX_BASE :: 32;
|
||||
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
|
||||
format_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string {
|
||||
is_pow2 :: proc(x: i64) -> bool {
|
||||
if (x <= 0) {
|
||||
return false;
|
||||
}
|
||||
return x&(x-1) == 0;
|
||||
}
|
||||
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to format_bits");
|
||||
}
|
||||
|
||||
a: [65]byte;
|
||||
i := a.count;
|
||||
if neg {
|
||||
u = -u;
|
||||
}
|
||||
|
||||
if is_pow2(cast(i64)base) {
|
||||
b := cast(u64)base;
|
||||
m := cast(uint)b - 1;
|
||||
for u >= b {
|
||||
i--;
|
||||
a[i] = digits[cast(uint)u & m];
|
||||
u >>= b;
|
||||
}
|
||||
i--;
|
||||
a[i] = digits[cast(uint)u];
|
||||
} else {
|
||||
b := cast(u64)base;
|
||||
for u >= b {
|
||||
i--;
|
||||
q := u / b;
|
||||
a[i] = digits[cast(uint)(u-q*b)];
|
||||
u = q;
|
||||
}
|
||||
|
||||
i--;
|
||||
a[i] = digits[cast(uint)u];
|
||||
}
|
||||
|
||||
if flags&Int_Flag.PREFIX != 0 {
|
||||
ok := true;
|
||||
match base {
|
||||
case 2: i--; a[i] = 'b';
|
||||
case 8: i--; a[i] = 'o';
|
||||
case 10: i--; a[i] = 'd';
|
||||
case 16: i--; a[i] = 'x';
|
||||
default: ok = false;
|
||||
}
|
||||
if ok {
|
||||
i--;
|
||||
a[i] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
i--; a[i] = '-';
|
||||
} else if flags&Int_Flag.PLUS != 0 {
|
||||
i--; a[i] = '+';
|
||||
} else if flags&Int_Flag.SPACE != 0 {
|
||||
i--; a[i] = ' ';
|
||||
}
|
||||
|
||||
|
||||
len := copy(buf, ...a[i:]);
|
||||
return cast(string)buf[:len];
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ to_odin_string :: proc(c: ^byte) -> string {
|
||||
s: string;
|
||||
s.data = c;
|
||||
for (c+s.count)^ != 0 {
|
||||
s.count += 1;
|
||||
s.count++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
+3
-3
@@ -52,7 +52,7 @@ mutex_lock :: proc(m: ^Mutex) {
|
||||
}
|
||||
}
|
||||
atomic.store(^m.owner, thread_id);
|
||||
m.recursion += 1;
|
||||
m.recursion++;
|
||||
}
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
thread_id := current_thread_id();
|
||||
@@ -68,7 +68,7 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
}
|
||||
atomic.store(^m.owner, thread_id);
|
||||
}
|
||||
m.recursion += 1;
|
||||
m.recursion++;
|
||||
return true;
|
||||
}
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
@@ -76,7 +76,7 @@ mutex_unlock :: proc(m: ^Mutex) {
|
||||
thread_id := current_thread_id();
|
||||
assert(thread_id == atomic.load(^m.owner));
|
||||
|
||||
m.recursion -= 1;
|
||||
m.recursion--;
|
||||
recursion = m.recursion;
|
||||
if recursion == 0 {
|
||||
atomic.store(^m.owner, thread_id);
|
||||
|
||||
+51
-7
@@ -92,7 +92,8 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
decode_rune :: proc(s: string) -> (rune, int) {
|
||||
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
|
||||
decode_rune :: proc(s: []byte) -> (rune, int) {
|
||||
n := s.count;
|
||||
if n < 1 {
|
||||
return RUNE_ERROR, 0;
|
||||
@@ -130,6 +131,46 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]byte)s); }
|
||||
decode_last_rune :: proc(s: []byte) -> (rune, int) {
|
||||
r: rune;
|
||||
size: int;
|
||||
start, end, limit: int;
|
||||
|
||||
end = s.count;
|
||||
if end == 0 {
|
||||
return RUNE_ERROR, 0;
|
||||
}
|
||||
start = end-1;
|
||||
r = cast(rune)s[start];
|
||||
if r < RUNE_SELF {
|
||||
return r, 1;
|
||||
}
|
||||
|
||||
|
||||
limit = max(end - UTF_MAX, 0);
|
||||
|
||||
start--;
|
||||
for start >= limit {
|
||||
if rune_start(s[start]) {
|
||||
break;
|
||||
}
|
||||
start--;
|
||||
}
|
||||
|
||||
start = max(start, 0);
|
||||
r, size = decode_rune(s[start:end]);
|
||||
if start+size != end {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
return r, size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
valid_rune :: proc(r: rune) -> bool {
|
||||
if r < 0 {
|
||||
return false;
|
||||
@@ -146,7 +187,7 @@ valid_string :: proc(s: string) -> bool {
|
||||
for i := 0; i < n; {
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si];
|
||||
@@ -174,25 +215,28 @@ valid_string :: proc(s: string) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
rune_count :: proc(s: string) -> int {
|
||||
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
|
||||
|
||||
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); }
|
||||
rune_count :: proc(s: []byte) -> int {
|
||||
count := 0;
|
||||
n := s.count;
|
||||
|
||||
for i := 0; i < n; {
|
||||
defer count += 1;
|
||||
defer count++;
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
size := cast(int)(x & 7);
|
||||
if i+size > n {
|
||||
i += 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
ar := accept_ranges[x>>4];
|
||||
|
||||
Reference in New Issue
Block a user