aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-02-26 00:44:26 +0000
committerGinger Bill <bill@gingerbill.org>2017-02-26 00:44:26 +0000
commitc59f6b7d0b582131bed4450bbb9aa1a71d5a01af (patch)
tree34957d43fa0241ffb6678302cae8e77fb7f8488b /core
parent67ed8a9a4ab8fdcfc77036c827b7dfa98025bc8b (diff)
++ -- statements; add strconv.odin (and replace some of the fmt procs); Fix ~ on 64 bit constants; Fix integer casts from smaller to larger size
Diffstat (limited to 'core')
-rw-r--r--core/_preload.odin6
-rw-r--r--core/atomic.odin4
-rw-r--r--core/decimal.odin258
-rw-r--r--core/fmt.odin210
-rw-r--r--core/hash.odin6
-rw-r--r--core/mem.odin6
-rw-r--r--core/strconv.odin337
-rw-r--r--core/strings.odin2
-rw-r--r--core/sync.odin6
-rw-r--r--core/utf8.odin58
10 files changed, 747 insertions, 146 deletions
diff --git a/core/_preload.odin b/core/_preload.odin
index de01bb244..56f9bfa45 100644
--- a/core/_preload.odin
+++ b/core/_preload.odin
@@ -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);
diff --git a/core/atomic.odin b/core/atomic.odin
index 3db437a4b..ec7900f0d 100644
--- a/core/atomic.odin
+++ b/core/atomic.odin
@@ -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();
diff --git a/core/decimal.odin b/core/decimal.odin
new file mode 100644
index 000000000..90582d20c
--- /dev/null
+++ b/core/decimal.odin
@@ -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;
+}
diff --git a/core/fmt.odin b/core/fmt.odin
index 80517ee95..bdb04d7e7 100644
--- a/core/fmt.odin
+++ b/core/fmt.odin
@@ -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");
- }
-
- 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';
+ panic("_write_int: unknown base, whoops");
}
- 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;
}
-
- if v == 0 {
- buffer_write_byte(fi.buf, '0');
- if fi.hash && width > 0 {
- buffer_write_byte(fi.buf, '.');
- }
+ 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 {
- 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;
- }
- }
+ str[0] = '+';
}
+ if fi.space && !fi.plus && str[0] == '+' {
+ str[0] = ' ';
+ }
- if width > 0 {
- fill: byte = ' ';
- match {
- case fi.zero: fill = '0';
- case fi.space: fill = ' ';
- }
+ if str[1] == 'N' && str[1] == 'I' {
+ buffer_write_string(fi.buf, str);
+ return;
+ }
- for width > 0 {
- width -= 1;
- buffer_write_byte(fi.buf, fill);
+ 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 {
+ pad(fi, str[1:]);
}
+
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++;
}
}
diff --git a/core/hash.odin b/core/hash.odin
index de1ffd0b6..fb3720176 100644
--- a/core/hash.odin
+++ b/core/hash.odin
@@ -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;
diff --git a/core/mem.odin b/core/mem.odin
index ce1c4a21c..5e89b38a9 100644
--- a/core/mem.odin
+++ b/core/mem.odin
@@ -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--;
}
diff --git a/core/strconv.odin b/core/strconv.odin
new file mode 100644
index 000000000..9f51808ad
--- /dev/null
+++ b/core/strconv.odin
@@ -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];
+}
+
diff --git a/core/strings.odin b/core/strings.odin
index bfc16a184..7439fff32 100644
--- a/core/strings.odin
+++ b/core/strings.odin
@@ -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;
}
diff --git a/core/sync.odin b/core/sync.odin
index e346c60d4..3126d6882 100644
--- a/core/sync.odin
+++ b/core/sync.odin
@@ -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);
diff --git a/core/utf8.odin b/core/utf8.odin
index 8720e1f20..1b304fde0 100644
--- a/core/utf8.odin
+++ b/core/utf8.odin
@@ -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];