mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-29 19:00:06 +00:00
Make the string type elements "immutable", akin to char const * in C
Allows for extra security and optimization benefits
This commit is contained in:
@@ -91,7 +91,7 @@ print :: proc(p: ^Parser, pretty := false) {
|
||||
}
|
||||
|
||||
create_from_string :: proc(src: string) -> (^Parser, bool) {
|
||||
return init(cast([]byte)src);
|
||||
return init(transmute([]byte)src);
|
||||
}
|
||||
|
||||
|
||||
@@ -726,8 +726,8 @@ calculate_binary_value :: proc(p: ^Parser, op: Kind, a, b: Value) -> (Value, boo
|
||||
case Kind.Add:
|
||||
n := len(a) + len(b);
|
||||
data := make([]byte, n);
|
||||
copy(data[:], cast([]byte)a);
|
||||
copy(data[len(a):], cast([]byte)b);
|
||||
copy(data[:], a);
|
||||
copy(data[len(a):], b);
|
||||
s := string(data);
|
||||
append(&p.allocated_strings, s);
|
||||
return s, true;
|
||||
|
||||
@@ -95,17 +95,17 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
||||
buf: [386]byte;
|
||||
|
||||
str := strconv.append_float(buf[1:], val, 'f', 2*ti.size, 8*ti.size);
|
||||
str = string(buf[:len(str)+1]);
|
||||
if str[1] == '+' || str[1] == '-' {
|
||||
str = str[1:];
|
||||
s := buf[:len(str)+1];
|
||||
if s[1] == '+' || s[1] == '-' {
|
||||
s = s[1:];
|
||||
} else {
|
||||
str[0] = '+';
|
||||
s[0] = '+';
|
||||
}
|
||||
if str[0] == '+' {
|
||||
str = str[1:];
|
||||
if s[0] == '+' {
|
||||
s = s[1:];
|
||||
}
|
||||
|
||||
write_string(b, str);
|
||||
write_string(b, string(s));
|
||||
|
||||
case Type_Info_Complex:
|
||||
return Marshal_Error.Unsupported_Type;
|
||||
|
||||
@@ -174,7 +174,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
|
||||
clone_string :: proc(s: string, allocator: mem.Allocator) -> string {
|
||||
n := len(s);
|
||||
b := make([]byte, n+1, allocator);
|
||||
copy(b, cast([]byte)s);
|
||||
copy(b, s);
|
||||
b[n] = 0;
|
||||
return string(b[:n]);
|
||||
}
|
||||
@@ -349,7 +349,7 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
|
||||
}
|
||||
|
||||
b := make([]byte, len(s) + 2*utf8.UTF_MAX, allocator);
|
||||
w := copy(b, cast([]byte)s[0:i]);
|
||||
w := copy(b, s[0:i]);
|
||||
loop: for i < len(s) {
|
||||
c := s[i];
|
||||
switch {
|
||||
|
||||
+30
-30
@@ -654,32 +654,32 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||
buf: [386]byte;
|
||||
|
||||
str := strconv.append_float(buf[1:], v, 'f', prec, bit_size);
|
||||
str = string(buf[:len(str)+1]);
|
||||
if str[1] == '+' || str[1] == '-' {
|
||||
str = str[1:];
|
||||
b := buf[:len(str)+1];
|
||||
if b[1] == '+' || b[1] == '-' {
|
||||
b = b[1:];
|
||||
} else {
|
||||
str[0] = '+';
|
||||
b[0] = '+';
|
||||
}
|
||||
|
||||
if fi.space && !fi.plus && str[0] == '+' {
|
||||
str[0] = ' ';
|
||||
if fi.space && !fi.plus && b[0] == '+' {
|
||||
b[0] = ' ';
|
||||
}
|
||||
|
||||
if len(str) > 1 && (str[1] == 'N' || str[1] == 'I') {
|
||||
strings.write_string(fi.buf, str);
|
||||
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
|
||||
strings.write_string(fi.buf, string(b));
|
||||
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:]);
|
||||
if fi.plus || b[0] != '+' {
|
||||
if fi.zero && fi.width_set && fi.width > len(b) {
|
||||
strings.write_byte(fi.buf, b[0]);
|
||||
fmt_write_padding(fi, fi.width - len(b));
|
||||
strings.write_string(fi.buf, string(b[1:]));
|
||||
} else {
|
||||
_pad(fi, str);
|
||||
_pad(fi, string(b));
|
||||
}
|
||||
} else {
|
||||
_pad(fi, str[1:]);
|
||||
_pad(fi, string(b[1:]));
|
||||
}
|
||||
|
||||
case 'e', 'E':
|
||||
@@ -688,32 +688,32 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||
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:];
|
||||
b := buf[:len(str)+1];
|
||||
if b[1] == '+' || b[1] == '-' {
|
||||
b = b[1:];
|
||||
} else {
|
||||
str[0] = '+';
|
||||
b[0] = '+';
|
||||
}
|
||||
|
||||
if fi.space && !fi.plus && str[0] == '+' {
|
||||
str[0] = ' ';
|
||||
if fi.space && !fi.plus && b[0] == '+' {
|
||||
b[0] = ' ';
|
||||
}
|
||||
|
||||
if len(str) > 1 && (str[1] == 'N' || str[1] == 'I') {
|
||||
strings.write_string(fi.buf, str);
|
||||
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
|
||||
strings.write_string(fi.buf, string(b));
|
||||
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:]);
|
||||
if fi.zero && fi.width_set && fi.width > len(b) {
|
||||
strings.write_byte(fi.buf, b[0]);
|
||||
fmt_write_padding(fi, fi.width - len(b));
|
||||
strings.write_string(fi.buf, string(b[1:]));
|
||||
} else {
|
||||
_pad(fi, str);
|
||||
_pad(fi, string(b));
|
||||
}
|
||||
} else {
|
||||
_pad(fi, str[1:]);
|
||||
_pad(fi, string(b[1:]));
|
||||
}
|
||||
|
||||
case 'h', 'H':
|
||||
@@ -1353,7 +1353,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
actual_field_count := len(info.names);
|
||||
|
||||
n := uintptr(info.soa_len);
|
||||
|
||||
|
||||
if info.soa_kind == .Slice {
|
||||
actual_field_count = len(info.names)-1; // len
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import "core:strconv"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, cast([]byte)str);
|
||||
return write(fd, transmute([]byte)str);
|
||||
}
|
||||
|
||||
write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) {
|
||||
|
||||
+21
-4
@@ -418,11 +418,24 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
|
||||
|
||||
|
||||
@builtin
|
||||
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
|
||||
return n;
|
||||
}
|
||||
@builtin
|
||||
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
if n > 0 {
|
||||
d := &dst[0];
|
||||
s := (transmute(Raw_String)src).data;
|
||||
mem_copy(d, s, n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@builtin
|
||||
copy :: proc{copy_slice, copy_from_string};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -559,6 +572,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
||||
a.len += arg_len;
|
||||
}
|
||||
}
|
||||
@builtin
|
||||
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) {
|
||||
append_elem(array, transmute([]E)arg, loc);
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
@@ -754,7 +771,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
|
||||
}
|
||||
}
|
||||
|
||||
@builtin append :: proc{append_elem, append_elems};
|
||||
@builtin append :: proc{append_elem, append_elems, append_elem_string};
|
||||
@builtin append_soa :: proc{append_soa_elem, append_soa_elems};
|
||||
|
||||
|
||||
@@ -1091,11 +1108,11 @@ _fnv64a :: proc(data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 {
|
||||
default_hash :: proc(data: []byte) -> u64 {
|
||||
return _fnv64a(data);
|
||||
}
|
||||
default_hash_string :: proc(s: string) -> u64 do return default_hash(([]byte)(s));
|
||||
default_hash_string :: proc(s: string) -> u64 do return default_hash(transmute([]byte)(s));
|
||||
|
||||
|
||||
source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
||||
hash := _fnv64a(cast([]byte)s.file_path);
|
||||
hash := _fnv64a(transmute([]byte)s.file_path);
|
||||
hash = hash ~ (u64(s.line) * 0x100000001b3);
|
||||
hash = hash ~ (u64(s.column) * 0x100000001b3);
|
||||
return hash;
|
||||
|
||||
@@ -369,17 +369,27 @@ memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_
|
||||
return 0;
|
||||
}
|
||||
|
||||
@private
|
||||
Raw_String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
};
|
||||
|
||||
string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||
x := transmute(Raw_String)a;
|
||||
y := transmute(Raw_String)b;
|
||||
switch {
|
||||
case len(a) != len(b): return false;
|
||||
case len(a) == 0: return true;
|
||||
case &a[0] == &b[0]: return true;
|
||||
case x.len != y.len: return false;
|
||||
case x.len == 0: return true;
|
||||
case x.data == y.data: return true;
|
||||
}
|
||||
return string_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
string_cmp :: proc "contextless" (a, b: string) -> int {
|
||||
return memory_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||
x := transmute(Raw_String)a;
|
||||
y := transmute(Raw_String)b;
|
||||
return memory_compare(x.data, y.data, min(x.len, y.len));
|
||||
}
|
||||
|
||||
string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
|
||||
@@ -398,10 +408,6 @@ cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||
}
|
||||
|
||||
cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
Raw_String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
};
|
||||
if s == nil do return "";
|
||||
ptr := (^byte)(s);
|
||||
n := cstring_len(s);
|
||||
|
||||
+3
-1
@@ -282,5 +282,7 @@ compare_f64s :: proc(a, b: f64) -> int {
|
||||
return 0;
|
||||
}
|
||||
compare_strings :: proc(a, b: string) -> int {
|
||||
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
x := transmute(mem.Raw_String)a;
|
||||
y := transmute(mem.Raw_String)b;
|
||||
return mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len));
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int)
|
||||
} else {
|
||||
s = "+Inf";
|
||||
}
|
||||
n := copy(buf, cast([]byte)s);
|
||||
n := copy(buf, transmute([]byte)s);
|
||||
return buf[:n];
|
||||
|
||||
case 0: // denormalized
|
||||
|
||||
@@ -187,8 +187,8 @@ parse_f64 :: proc(s: string) -> f64 {
|
||||
|
||||
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
n := 0;
|
||||
if b do n = copy(buf, cast([]byte)"true");
|
||||
else do n = copy(buf, cast([]byte)"false");
|
||||
if b do n = copy(buf, "true");
|
||||
else do n = copy(buf, "false");
|
||||
return string(buf[:n]);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
|
||||
}
|
||||
write_string :: inline proc(buf: []byte, i: ^int, s: string) {
|
||||
if i^ < len(buf) {
|
||||
n := copy(buf[i^:], cast([]byte)s);
|
||||
n := copy(buf[i^:], s);
|
||||
i^ += n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ write_rune :: proc(b: ^Builder, r: rune) -> int {
|
||||
}
|
||||
|
||||
write_string :: proc(b: ^Builder, s: string) {
|
||||
write_bytes(b, cast([]byte)s);
|
||||
write_bytes(b, transmute([]byte)s);
|
||||
}
|
||||
|
||||
write_bytes :: proc(b: ^Builder, x: []byte) {
|
||||
|
||||
+14
-14
@@ -5,14 +5,14 @@ import "core:unicode/utf8"
|
||||
|
||||
clone :: proc(s: string, allocator := context.allocator) -> string {
|
||||
c := make([]byte, len(s)+1, allocator);
|
||||
copy(c, cast([]byte)s);
|
||||
copy(c, 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);
|
||||
copy(c, s);
|
||||
c[len(s)] = 0;
|
||||
return cstring(&c[0]);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ clone_to_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
|
||||
@(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);
|
||||
copy(c, s);
|
||||
c[len(s)] = 0;
|
||||
return string(c[:len(s)]);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ new_string :: proc(s: string, allocator := context.allocator) -> string {
|
||||
@(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);
|
||||
copy(c, s);
|
||||
c[len(s)] = 0;
|
||||
return cstring(&c[0]);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ string_from_ptr :: proc(ptr: ^byte, len: int) -> string {
|
||||
}
|
||||
|
||||
compare :: proc(lhs, rhs: string) -> int {
|
||||
return mem.compare(cast([]byte)lhs, cast([]byte)rhs);
|
||||
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs);
|
||||
}
|
||||
|
||||
contains_rune :: proc(s: string, r: rune) -> int {
|
||||
@@ -130,10 +130,10 @@ join :: proc(a: []string, sep: string, allocator := context.allocator) -> string
|
||||
}
|
||||
|
||||
b := make([]byte, n, allocator);
|
||||
i := copy(b, cast([]byte)a[0]);
|
||||
i := copy(b, a[0]);
|
||||
for s in a[1:] {
|
||||
i += copy(b[i:], cast([]byte)sep);
|
||||
i += copy(b[i:], cast([]byte)s);
|
||||
i += copy(b[i:], sep);
|
||||
i += copy(b[i:], s);
|
||||
}
|
||||
return string(b);
|
||||
}
|
||||
@@ -150,7 +150,7 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
|
||||
b := make([]byte, n, allocator);
|
||||
i := 0;
|
||||
for s in a {
|
||||
i += copy(b[i:], cast([]byte)s);
|
||||
i += copy(b[i:], s);
|
||||
}
|
||||
return string(b);
|
||||
}
|
||||
@@ -416,7 +416,7 @@ repeat :: proc(s: string, count: int, allocator := context.allocator) -> string
|
||||
}
|
||||
|
||||
b := make([]byte, len(s)*count, allocator);
|
||||
i := copy(b, cast([]byte)s);
|
||||
i := copy(b, s);
|
||||
for i < len(b) { // 2^N trick to reduce the need to copy
|
||||
copy(b[i:], b[:i]);
|
||||
i *= 2;
|
||||
@@ -460,11 +460,11 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) ->
|
||||
} else {
|
||||
j += index(s[start:], old);
|
||||
}
|
||||
w += copy(t[w:], cast([]byte)s[start:j]);
|
||||
w += copy(t[w:], cast([]byte)new);
|
||||
w += copy(t[w:], s[start:j]);
|
||||
w += copy(t[w:], new);
|
||||
start = j + len(old);
|
||||
}
|
||||
w += copy(t[w:], cast([]byte)s[start:]);
|
||||
w += copy(t[w:], s[start:]);
|
||||
output = string(t[0:w]);
|
||||
return;
|
||||
}
|
||||
@@ -705,7 +705,7 @@ reverse :: proc(s: string, allocator := context.allocator) -> string {
|
||||
for len(str) > 0 {
|
||||
_, w := utf8.decode_rune_in_string(str);
|
||||
i -= w;
|
||||
copy(buf[i:], cast([]byte)str[:w]);
|
||||
copy(buf[i:], str[:w]);
|
||||
str = str[w:];
|
||||
}
|
||||
return string(buf);
|
||||
|
||||
@@ -752,14 +752,16 @@ utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
|
||||
return nil;
|
||||
}
|
||||
|
||||
n := multi_byte_to_wide_char(CP_UTF8, MB_ERR_INVALID_CHARS, cstring(&s[0]), i32(len(s)), nil, 0);
|
||||
b := transmute([]byte)s;
|
||||
cstr := cstring(&b[0]);
|
||||
n := multi_byte_to_wide_char(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, i32(len(s)), nil, 0);
|
||||
if n == 0 {
|
||||
return nil;
|
||||
}
|
||||
|
||||
text := make([]u16, n+1, allocator);
|
||||
|
||||
n1 := multi_byte_to_wide_char(CP_UTF8, MB_ERR_INVALID_CHARS, cstring(&s[0]), i32(len(s)), Wstring(&text[0]), i32(n));
|
||||
n1 := multi_byte_to_wide_char(CP_UTF8, MB_ERR_INVALID_CHARS, cstr, i32(len(s)), Wstring(&text[0]), i32(n));
|
||||
if n1 == 0 {
|
||||
delete(text, allocator);
|
||||
return nil;
|
||||
|
||||
@@ -90,7 +90,7 @@ encode_rune :: proc(c: rune) -> ([4]u8, int) {
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
decode_rune_in_string :: inline proc(s: string) -> (rune, int) do return decode_rune(cast([]u8)s);
|
||||
decode_rune_in_string :: inline proc(s: string) -> (rune, int) do return decode_rune(transmute([]u8)s);
|
||||
decode_rune :: proc(s: []u8) -> (rune, int) {
|
||||
n := len(s);
|
||||
if n < 1 {
|
||||
@@ -130,7 +130,7 @@ decode_rune :: proc(s: []u8) -> (rune, int) {
|
||||
|
||||
|
||||
|
||||
decode_last_rune_in_string :: inline proc(s: string) -> (rune, int) do return decode_last_rune(cast([]u8)s);
|
||||
decode_last_rune_in_string :: inline proc(s: string) -> (rune, int) do return decode_last_rune(transmute([]u8)s);
|
||||
decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||
r: rune;
|
||||
size: int;
|
||||
@@ -260,7 +260,7 @@ valid_string :: proc(s: string) -> bool {
|
||||
|
||||
rune_start :: inline proc(b: u8) -> bool do return b&0xc0 != 0x80;
|
||||
|
||||
rune_count_in_string :: inline proc(s: string) -> int do return rune_count(cast([]u8)s);
|
||||
rune_count_in_string :: inline proc(s: string) -> int do return rune_count(transmute([]u8)s);
|
||||
rune_count :: proc(s: []u8) -> int {
|
||||
count := 0;
|
||||
n := len(s);
|
||||
|
||||
Reference in New Issue
Block a user