#![allow(non_snake_case)]
pub fn fail() -> ! {
crate::ported::crt::CRT_done();
std::process::abort();
}
pub fn String_cat(s1: &str, s2: &str) -> String {
let mut out = String::with_capacity(s1.len() + s2.len());
out.push_str(s1);
out.push_str(s2);
out
}
pub fn String_trim(input: &str) -> String {
input
.trim_matches(|c| c == ' ' || c == '\t' || c == '\n')
.to_string()
}
pub fn String_split(s: &str, sep: char) -> Vec<String> {
let mut out: Vec<String> = Vec::new();
let mut rest = s;
while let Some(idx) = rest.find(sep) {
out.push(rest[..idx].to_string());
rest = &rest[idx + sep.len_utf8()..];
}
if !rest.is_empty() {
out.push(rest.to_string());
}
out
}
pub fn String_splitFirst(s: &str, sep: char) -> Vec<String> {
let mut out: Vec<String> = Vec::new();
let mut rest = s;
if let Some(idx) = rest.find(sep) {
out.push(rest[..idx].to_string());
rest = &rest[idx + sep.len_utf8()..];
}
if !rest.is_empty() {
out.push(rest.to_string());
}
out
}
pub fn String_contains_i(s1: &str, s2: &str, multi: bool) -> bool {
if multi && s2.contains('|') {
let hay = s1.to_ascii_lowercase();
for needle in String_split(s2, '|') {
if hay.contains(&needle.to_ascii_lowercase()) {
return true;
}
}
false
} else {
s1.to_ascii_lowercase().contains(&s2.to_ascii_lowercase())
}
}
pub fn String_startsWith(s: &str, match_: &str) -> bool {
s.starts_with(match_)
}
pub fn String_eq(s1: &str, s2: &str) -> bool {
s1 == s2
}
pub fn String_eq_nullable(s1: Option<&str>, s2: Option<&str>) -> bool {
match (s1, s2) {
(None, None) => true,
(Some(a), Some(b)) => a == b,
_ => false,
}
}
pub fn String_strchrnul(s: &str, c: u8) -> usize {
match s.bytes().position(|b| b == c) {
Some(i) => i,
None => s.len(),
}
}
pub fn String_safeStrncpy(dest: &mut [u8], src: &[u8]) -> usize {
let size = dest.len();
assert!(size > 0);
let mut i = 0;
while i < size - 1 && i < src.len() && src[i] != 0 {
dest[i] = src[i];
i += 1;
}
dest[i] = 0;
i
}
pub fn strnlen(str: &[u8], max_len: usize) -> usize {
for len in 0..max_len {
if str[len] == 0 {
return len;
}
}
max_len
}
pub fn compareRealNumbers(a: f64, b: f64) -> i32 {
let result = (a > b) as i32 - (b > a) as i32;
if result != 0 {
return result;
}
(!a.is_nan()) as i32 - (!b.is_nan()) as i32
}
pub fn saturatingSub(a: u64, b: u64) -> u64 {
if a > b {
a - b
} else {
0
}
}
pub fn sumPositiveValues(array: &[f64]) -> f64 {
let mut sum = 0.0;
for &v in array {
if v > 0.0 {
sum += v;
}
}
sum
}
pub fn countDigits(n: usize, base: usize) -> usize {
assert!(base > 1);
let mut res = 1;
let mut limit = base;
while n >= limit {
res += 1;
if limit > usize::MAX / base {
break;
}
limit *= base;
}
res
}
const MOD37_BIT_POSITION: [u8; 37] = [
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29, 10,
12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18,
];
pub fn countTrailingZeros(x: u32) -> u32 {
MOD37_BIT_POSITION[((x.wrapping_neg() & x) % 37) as usize] as u32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn string_cat_concatenates() {
assert_eq!(String_cat("foo", "bar"), "foobar");
assert_eq!(String_cat("", "x"), "x");
assert_eq!(String_cat("x", ""), "x");
}
#[test]
fn string_trim_only_space_tab_newline() {
assert_eq!(String_trim(" \t hi \n\t"), "hi");
assert_eq!(String_trim("\n\nabc"), "abc");
assert_eq!(String_trim("\rhi\r"), "\rhi\r");
}
#[test]
fn string_split_keeps_interior_drops_trailing_empty() {
assert_eq!(String_split("a,b,c", ','), vec!["a", "b", "c"]);
assert_eq!(String_split("a,,b", ','), vec!["a", "", "b"]);
assert_eq!(String_split("a,", ','), vec!["a"]);
assert_eq!(String_split(",a", ','), vec!["", "a"]);
assert!(String_split("", ',').is_empty());
assert_eq!(String_split("abc", ','), vec!["abc"]);
}
#[test]
fn string_split_first_only_first_sep() {
assert_eq!(String_splitFirst("a,b,c", ','), vec!["a", "b,c"]);
assert_eq!(String_splitFirst("nocomma", ','), vec!["nocomma"]);
assert_eq!(String_splitFirst("a,", ','), vec!["a"]);
}
#[test]
fn string_contains_i_case_insensitive_and_multi() {
assert!(String_contains_i("Hello World", "hello", false));
assert!(!String_contains_i("Hello", "xyz", false));
assert!(String_contains_i("firefox", "chrome|FOX|edge", true));
assert!(!String_contains_i("safari", "chrome|fox|edge", true));
assert!(!String_contains_i("firefox", "chrome|fox", false));
}
#[test]
fn string_starts_with_byte_prefix() {
assert!(String_startsWith("firefox", "fire"));
assert!(String_startsWith("abc", "")); assert!(String_startsWith("abc", "abc")); assert!(!String_startsWith("abc", "abcd")); assert!(!String_startsWith("abc", "b"));
assert!(String_startsWith("áb", "\u{e1}")); }
#[test]
fn string_eq_byte_exact() {
assert!(String_eq("abc", "abc"));
assert!(!String_eq("abc", "abd"));
assert!(!String_eq("abc", "ab"));
assert!(String_eq("", ""));
assert!(!String_eq("", "x"));
}
#[test]
fn string_eq_nullable_null_semantics() {
assert!(String_eq_nullable(None, None));
assert!(String_eq_nullable(Some("x"), Some("x")));
assert!(!String_eq_nullable(Some("x"), Some("y")));
assert!(!String_eq_nullable(Some("x"), None));
assert!(!String_eq_nullable(None, Some("x")));
assert!(String_eq_nullable(Some(""), Some("")));
assert!(!String_eq_nullable(Some(""), None));
}
#[test]
fn string_strchrnul_index_or_len() {
assert_eq!(String_strchrnul("a=b", b'='), 1);
assert_eq!(String_strchrnul("abc", b'a'), 0);
assert_eq!(String_strchrnul("abc", b'z'), 3);
assert_eq!(String_strchrnul("", b'x'), 0);
assert_eq!(String_strchrnul("a=b=c", b'='), 1);
}
#[test]
fn string_safe_strncpy_truncates_and_terminates() {
let mut buf = [0u8; 6];
assert_eq!(String_safeStrncpy(&mut buf, b"hello"), 5);
assert_eq!(&buf, b"hello\0");
let mut buf = [0xFFu8; 4];
assert_eq!(String_safeStrncpy(&mut buf, b"hello"), 3);
assert_eq!(&buf, b"hel\0");
let mut buf = [0xFFu8; 1];
assert_eq!(String_safeStrncpy(&mut buf, b"x"), 0);
assert_eq!(&buf, b"\0");
let mut buf = [0xFFu8; 8];
assert_eq!(String_safeStrncpy(&mut buf, b""), 0);
assert_eq!(buf[0], 0);
let mut buf = [0xFFu8; 8];
assert_eq!(String_safeStrncpy(&mut buf, b"ab\0cd"), 2);
assert_eq!(&buf[..3], b"ab\0");
let mut buf = [0u8; 2];
assert_eq!(String_safeStrncpy(&mut buf, "á".as_bytes()), 1);
assert_eq!(&buf, &[0xC3u8, 0x00]);
}
#[test]
fn strnlen_stops_at_nul_or_cap() {
assert_eq!(strnlen(b"hello\0world", 11), 5);
assert_eq!(strnlen(b"hello", 3), 3);
assert_eq!(strnlen(b"abc\0", 3), 3);
assert_eq!(strnlen(b"abc\0", 4), 3);
assert_eq!(strnlen(b"abc", 0), 0);
assert_eq!(strnlen(b"\0abc", 4), 0);
}
#[test]
fn compare_real_numbers_orders_and_nan_last() {
assert_eq!(compareRealNumbers(1.0, 2.0), -1);
assert_eq!(compareRealNumbers(2.0, 1.0), 1);
assert_eq!(compareRealNumbers(1.0, 1.0), 0);
assert_eq!(compareRealNumbers(f64::NAN, 1.0), -1);
assert_eq!(compareRealNumbers(1.0, f64::NAN), 1);
assert_eq!(compareRealNumbers(f64::NAN, f64::NAN), 0);
}
#[test]
fn sum_positive_values_skips_nan_and_nonpositive() {
assert_eq!(sumPositiveValues(&[1.0, 2.0, 3.0]), 6.0);
assert_eq!(sumPositiveValues(&[1.0, -2.0, 3.0]), 4.0);
assert_eq!(sumPositiveValues(&[f64::NAN, 5.0, -1.0]), 5.0);
assert_eq!(sumPositiveValues(&[-1.0, -2.0]), 0.0);
assert_eq!(sumPositiveValues(&[]), 0.0);
}
#[test]
fn count_digits_base10_and_base2() {
assert_eq!(countDigits(0, 10), 1);
assert_eq!(countDigits(9, 10), 1);
assert_eq!(countDigits(10, 10), 2);
assert_eq!(countDigits(999, 10), 3);
assert_eq!(countDigits(1000, 10), 4);
assert_eq!(countDigits(0, 2), 1);
assert_eq!(countDigits(1, 2), 1);
assert_eq!(countDigits(2, 2), 2);
assert_eq!(countDigits(255, 16), 2);
}
#[test]
fn count_trailing_zeros_matches_intrinsic() {
for shift in 0..31u32 {
let x = 1u32 << shift;
assert_eq!(countTrailingZeros(x), x.trailing_zeros(), "x={x:#x}");
}
assert_eq!(countTrailingZeros(0b1011000), 3);
assert_eq!(countTrailingZeros(12), 2);
}
}