diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index a2f1166ac..6903b9bdb 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { // print* procedures return the number of bytes written -print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); } -print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); } -println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); } -println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); } -printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); } -printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); } +print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); } +println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); } +printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); } + +eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); } +eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); } +eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); } + + +@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); } +@(deprecated="prefer eprintf") println_err :: proc(args: ..any) -> int { return eprintln(..args); } +@(deprecated="prefer eprintln") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); } // aprint* procedures return a string that was allocated with the current context diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 8130668b3..d1678a1b2 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -304,10 +304,8 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { write_byte(buf, info.signed ? 'i' : 'u'); write_i64(buf, i64(8*ti.size), 10); switch info.endianness { - case rt.Type_Info_Endianness.Little: - write_string(buf, "le"); - case rt.Type_Info_Endianness.Big: - write_string(buf, "be"); + case .Little: write_string(buf, "le"); + case .Big: write_string(buf, "be"); } } case rt.Type_Info_Rune: diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 022a84e9e..c401dbdf3 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -40,7 +40,7 @@ Type_Info_Enum_Value :: union { u8, u16, u32, u64, uint, uintptr, }; -Type_Info_Endianness :: enum u8 { +Platform_Endianness :: enum u8 { Platform = 0, Little = 1, Big = 2, @@ -48,7 +48,7 @@ Type_Info_Endianness :: enum u8 { // Variant Types Type_Info_Named :: struct {name: string, base: ^Type_Info}; -Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; +Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness}; Type_Info_Rune :: struct {}; Type_Info_Float :: struct {}; Type_Info_Complex :: struct {}; diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index ac78f78dc..447178bc3 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -205,7 +205,11 @@ itoa :: proc(buf: []byte, i: int) -> string { atoi :: proc(s: string) -> int { return parse_int(s); } +atof :: proc(s: string) -> f64 { + return parse_f64(s); +} +ftoa :: append_float; append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { return string(generic_ftoa(buf, f, fmt, prec, bit_size)); } diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 68f1a7ceb..f7dac04ba 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) { reserve(&b.buf, cap); } +reset_builder :: proc(b: ^Builder) { + clear(&b.buf); +} + builder_from_slice :: proc(backing: []byte) -> Builder { s := transmute(mem.Raw_Slice)backing; d := mem.Raw_Dynamic_Array{ diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 8f9db86be..0c9ffa7d3 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string { return string(b); } +@private +_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string { + s, n := s_, n_; + + if n == 0 { + return nil; + } + + if sep == "" { + l := utf8.rune_count_in_string(s); + if n < 0 || n > l { + n = l; + } + + res := make([dynamic]string, n); + for i := 0; i < n-1; i += 1 { + r, w := utf8.decode_rune_in_string(s); + res[i] = s[:w]; + s = s[w:]; + } + if n > 0 { + res[n-1] = s; + } + return res[:]; + } + + if n < 0 { + n = count(s, sep) + 1; + } + + res := make([dynamic]string, n); + + n -= 1; + + i := 0; + for ; i < n; i += 1 { + m := index(s, sep); + if m < 0 { + break; + } + res[i] = s[:m+sep_save]; + s = s[m+len(sep):]; + } + res[i] = s; + + return res[:i+1]; +} + +split :: inline proc(s, sep: string, allocator := context.allocator) -> []string { + return _split(s, sep, 0, -1, allocator); +} + +split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string { + return _split(s, sep, 0, n, allocator); +} + +split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string { + return _split(s, sep, len(sep), -1, allocator); +} + +split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string { + return _split(s, sep, len(sep), n, allocator); +} + + + + index_byte :: proc(s: string, c: byte) -> int { for i := 0; i < len(s); i += 1 { if s[i] == c do return i; @@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int { return -1; } + + +@private PRIME_RABIN_KARP :: 16777619; + index :: proc(s, substr: string) -> int { + hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { + for i := 0; i < len(s); i += 1 { + hash = hash*PRIME_RABIN_KARP + u32(s[i]); + } + sq := u32(PRIME_RABIN_KARP); + for i := len(s); i > 0; i >>= 1 { + if (i & 1) != 0 { + pow *= sq; + } + sq *= sq; + } + return; + } + n := len(substr); switch { case n == 0: @@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int { return -1; } - for i := 0; i < len(s)-n+1; i += 1 { - x := s[i:i+n]; - if x == substr { + hash, pow := hash_str_rabin_karp(substr); + h: u32; + for i := 0; i < n; i += 1 { + h = h*PRIME_RABIN_KARP + u32(s[i]); + } + if h == hash && s[:n] == substr { + return 0; + } + for i := n; i < len(s); /**/ { + h *= PRIME_RABIN_KARP; + h += u32(s[i]); + h -= pow * u32(s[i-n]); + i += 1; + if h == hash && s[i-n:i] == substr { + return i - n; + } + } + return -1; +} + +last_index :: proc(s, substr: string) -> int { + hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { + for i := len(s) - 1; i >= 0; i -= 1 { + hash = hash*PRIME_RABIN_KARP + u32(s[i]); + } + sq := u32(PRIME_RABIN_KARP); + for i := len(s); i > 0; i >>= 1 { + if (i & 1) != 0 { + pow *= sq; + } + sq *= sq; + } + return; + } + + n := len(substr); + switch { + case n == 0: + return len(s); + case n == 1: + return last_index_byte(s, substr[0]); + case n == len(s): + return substr == s ? 0 : -1; + case n > len(s): + return -1; + } + + hash, pow := hash_str_rabin_karp_reverse(substr); + last := len(s) - n; + h: u32; + for i := len(s)-1; i >= last; i -= 1 { + h = h*PRIME_RABIN_KARP + u32(s[i]); + } + if h == hash && s[last:] == substr { + return last; + } + + for i := last-1; i >= 0; i -= 1 { + h *= PRIME_RABIN_KARP; + h += u32(s[i]); + h -= pow * u32(s[i+n]); + if h == hash && s[i:i+n] == substr { return i; } } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index eec7da45a..2c8148501 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -4,6 +4,7 @@ import "core:fmt" import "core:mem" import "core:os" import "core:reflect" +import "core:strings" import "intrinsics" when os.OS == "windows" { @@ -1189,7 +1190,15 @@ where_clauses :: proc() { } main :: proc() { - when true { + x := "foobarbaz"; + i : int; + i = strings.last_index(x, "foo"); fmt.println(i); + i = strings.last_index(x, "bar"); fmt.println(i); + i = strings.last_index(x, "baz"); fmt.println(i); + i = strings.last_index(x, "asd"); fmt.println(i); + i = strings.last_index(x, "a"); fmt.println(i); + i = strings.last_index(x, "ba"); fmt.println(i); + when false { general_stuff(); union_type(); parametric_polymorphism(); @@ -1212,3 +1221,4 @@ main :: proc() { where_clauses(); } } + diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b4abf41a7..5d1c07a67 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -55,7 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = { -String const ODIN_VERSION = str_lit("0.10.1"); +String const ODIN_VERSION = str_lit("0.10.2");