296 lines
7.9 KiB
Plaintext
296 lines
7.9 KiB
Plaintext
string_view :: inline (s: string, start_index: s64, view_count: s64) -> string {
|
|
assert(view_count >= 0 && start_index >= 0);
|
|
if view_count < 0 || start_index < 0 || start_index >= s.count return "";
|
|
|
|
new_count := view_count;
|
|
if start_index + view_count > s.count {
|
|
new_count = s.count - start_index;
|
|
}
|
|
|
|
return { new_count, s.data + start_index };
|
|
}
|
|
|
|
to_string :: inline (s: *u8, length: s64) -> string { // We should probably deprecate this in favor of your using string.{...}?
|
|
if !s return "";
|
|
|
|
result: string = ---;
|
|
result.count = length;
|
|
result.data = s;
|
|
return result;
|
|
}
|
|
|
|
// Intended for C strings in fixed-size arrays that may or may not be zero-terminated.
|
|
// It stops at the first zero in c_string.data but does not exceed c_string.count.
|
|
to_string :: (c_string: [] u8) -> string {
|
|
if c_string.count == 0 return "";
|
|
|
|
result: string = ---;
|
|
result.data = c_string.data;
|
|
length := 0;
|
|
while c_string[length] && length < c_string.count {
|
|
length += 1;
|
|
}
|
|
result.count = length;
|
|
return result;
|
|
}
|
|
|
|
// The following functions:
|
|
//
|
|
// to_string :: inline (s: *u8) -> string;
|
|
// c_style_strlen :: (x: *u8) -> s64;
|
|
//
|
|
// are in Runtime_Support.jai and can be called from anywhere.
|
|
|
|
// Allocates memory.
|
|
to_c_string :: (s: string) -> *u8 {
|
|
result : *u8 = alloc(s.count + 1);
|
|
memcpy(result, s.data, s.count);
|
|
result[s.count] = 0;
|
|
return result;
|
|
}
|
|
|
|
|
|
// Note: Right now when code is generated, c + A - a
|
|
// doesn't get constexpr evaluation evoked on the A - a
|
|
// because it parses into the AST as (c + A) - a, and we
|
|
// do not do tree rearrangement for constexpr evaluation.
|
|
// (And I am not sure that we should). -jblow, 25 April 2018.
|
|
|
|
// Maybe to_upper, to_lower, etc should not even be in Basic... -jblow
|
|
|
|
// These are locale indepdent, only support english characters, and do not support utf8.
|
|
|
|
to_upper :: (c: u8) -> u8 {
|
|
if c >= #char "a" && c <= #char "z" return c + #char "A" - #char "a";
|
|
else return c;
|
|
}
|
|
|
|
to_lower :: (c: u8) -> u8 {
|
|
if (c >= #char "A" && c <= #char "Z") return c + #char "a" - #char "A";
|
|
else return c;
|
|
}
|
|
|
|
is_alpha :: (c: u8) -> bool {
|
|
return (c >= #char "a" && c <= #char "z") || (c >= #char "A" && c <= #char "Z");
|
|
}
|
|
|
|
is_digit :: (c: u8) -> bool {
|
|
return c >= #char "0" && c <= #char "9";
|
|
}
|
|
|
|
is_alnum :: (c: u8) -> bool { // This also includes underscore!
|
|
return is_alpha(c) || is_digit(c) || c == #char "_";
|
|
}
|
|
|
|
is_space :: (c: u8) -> bool {
|
|
return c == #char " " || c == #char "\t" || c == #char "\r" || c == #char "\n";
|
|
}
|
|
|
|
is_print :: (c: u8) -> bool {
|
|
// True for any character from space to tilde (DEL not included).
|
|
return c >= 0x20 && c < 0x7F;
|
|
}
|
|
|
|
advance :: inline (s: *string, amount: s64 = 1) {
|
|
assert(amount >= 0);
|
|
assert(s.count >= amount);
|
|
s.count -= amount;
|
|
s.data += amount;
|
|
}
|
|
|
|
advance :: inline (s: string, amount: s64 = 1) -> string {
|
|
assert(amount >= 0);
|
|
assert(s.count >= amount);
|
|
|
|
t: string = ---;
|
|
t.count = s.count - amount;
|
|
t.data = s.data + amount;
|
|
return t;
|
|
}
|
|
|
|
|
|
temp_c_string :: (s: string) -> *u8 {
|
|
result : *u8 = temporary_alloc(s.count + 1);
|
|
memcpy(result, s.data, s.count);
|
|
result[s.count] = 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
copy_temporary_string :: inline (s: string) -> string {
|
|
return copy_string(s,, temp);
|
|
}
|
|
|
|
copy_string :: (s: string) -> string {
|
|
if !s.count return "";
|
|
|
|
copy := alloc_string(s.count);
|
|
if !copy.data return "";
|
|
memcpy(copy.data, s.data, s.count);
|
|
return copy;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
@Bug: We want to have string_to_float be parameterized,
|
|
but it doesn't quite work consistently for some reason.
|
|
In both LLVM and x64, the procedures appear to return
|
|
0 sometimes (but not always, depending on what is going on
|
|
in the calling procedure). -jblow, 19 February 2017
|
|
|
|
Test code:
|
|
|
|
f1 := string_to_float("42.6");
|
|
print("f1 is type %, value %\n", type_of(f1), f1);
|
|
|
|
f2 := string_to_float64("42.6");
|
|
print("f2 is type %, value %\n", type_of(f2), f2);
|
|
|
|
f3 := string_to_float_old("42.6");
|
|
print("f3 is type %, value %\n", type_of(f3), f3);
|
|
|
|
|
|
string_to_float :: #bake_constants string_to_float_type_T (T = float);
|
|
string_to_float64 :: #bake_constants string_to_float_type_T (T = float64);
|
|
|
|
string_to_float_type_T :: (_arg: string) -> result: $T, success: bool, remainder: string {
|
|
arg := eat_spaces(_arg);
|
|
|
|
if !arg {
|
|
return 0, false, arg;
|
|
}
|
|
|
|
found_decimal := false;
|
|
|
|
// @Temporary:
|
|
// See how much of the string is a digit, +, -, ., or e.
|
|
limit := arg.count;
|
|
for 0..arg.count-1 {
|
|
c := arg[it];
|
|
if (c >= #char "0") && (c <= #char "9") {
|
|
// We are good.
|
|
} else if c == #char "." {
|
|
// We are good.
|
|
} else if (c == #char "-") || (c == #char "+") || (c == #char "e") {
|
|
// We are good.
|
|
} else {
|
|
limit = it;
|
|
break;
|
|
}
|
|
}
|
|
|
|
substring := arg;
|
|
substring.count = limit;
|
|
|
|
remainder := arg;
|
|
advance(*remainder, limit);
|
|
|
|
// @Temporary @Speed @Ugh
|
|
cs := temp_c_string(substring);
|
|
result := cast(T) atof(cs);
|
|
|
|
return result, true, remainder;
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
//
|
|
// @Cleanup! We would like to just do:
|
|
//
|
|
// to_integer :: #bake_arguments string_to_int(base=10);
|
|
//
|
|
// But this causes dead code elimination to think string_to_int is live,
|
|
// even if it's not. So it would be good to come up with a way to make
|
|
// this work better! In the meantime...
|
|
//
|
|
to_integer :: (s: string) -> result: int, success: bool, remainder: string {
|
|
result, success, remainder := string_to_int(s);
|
|
return result, success, remainder;
|
|
}
|
|
|
|
string_to_int :: (t: string, base := 10, $T := int) -> result: T, success: bool, remainder: string {
|
|
//
|
|
// This string_to_int might be a little slower than max speed because we multiply by 'sign' for
|
|
// each digit. Our original approach did not do this, but rather we just accumulated into a
|
|
// positive value and then negated at the end if we saw a -. But this does not let us parse the
|
|
// maximum negative number without overflowing the positive number, which works, *if* you are
|
|
// not doing arithmetic bounds checks. We could have done #no_abc on this procedure, but
|
|
// I decided it's worthwhile to just try to preserve the ability to report genuine overflows,
|
|
// so I did 'the clean version' here. -jblow, 4 July 2023
|
|
//
|
|
assert(base == 16 || base <= 10);
|
|
|
|
s := eat_spaces(t);
|
|
|
|
if !s return 0, false, "";
|
|
|
|
sign : T = 1;
|
|
|
|
#if #run type_info(T).signed {
|
|
if s[0] == #char "-" {
|
|
sign = -1;
|
|
advance(*s, 1);
|
|
s = eat_spaces(s);
|
|
} else if s[0] == #char "+" {
|
|
advance(*s, 1);
|
|
s = eat_spaces(s);
|
|
}
|
|
}
|
|
|
|
sum: T = 0;
|
|
cursor := 0;
|
|
|
|
// @Incomplete: We should probably check for overflows…
|
|
if base == 16 {
|
|
while cursor < s.count {
|
|
c := s[cursor];
|
|
|
|
value: u8 = ---;
|
|
if is_digit(c) {
|
|
value = c - #char "0";
|
|
} else if (c >= #char "a") && (c <= #char "f") {
|
|
value = c - #char "a" + 10;
|
|
} else if (c >= #char "A") && (c <= #char "F") {
|
|
value = c - #char "A" + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
sum *= cast(T) base;
|
|
sum += sign * cast(T)value;
|
|
|
|
cursor += 1;
|
|
}
|
|
} else {
|
|
while cursor < s.count {
|
|
c := s[cursor];
|
|
if !is_digit(c) break;
|
|
|
|
digit := c - #char "0";
|
|
if digit >= base break;
|
|
|
|
sum *= cast(T) base;
|
|
sum += sign*cast(T)digit;
|
|
|
|
cursor += 1;
|
|
}
|
|
}
|
|
|
|
success := (cursor != 0);
|
|
advance(*s, cursor);
|
|
|
|
return sum, success, s;
|
|
}
|
|
|
|
eat_spaces :: (_s: string) -> string {
|
|
s := _s;
|
|
while s {
|
|
if (s[0] != #char " ") && (s[0] != 9) break; // 9 is horizontal tab.
|
|
advance(*s, 1);
|
|
}
|
|
|
|
return s;
|
|
}
|