Files
Viper_VRTE/string.vp
T
2026-09-16 16:07:35 +08:00

640 lines
21 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from stdint import *
import t, c
import stdio
# String copy function
def strcpy(dest: str, src: str) -> str:
if dest == None or src == None: return None
original_dest: str = dest
for s in src:
dest[0] = s
dest += 1
dest[0] = 0
return original_dest
# String concatenate function
def strcat(dest: str, src: str) -> str:
if dest == None or src == None: return dest
original_dest: str = dest
# Find end of dest
while dest[0] != '\0':
dest += 1
# Copy src
for s in src:
dest[0] = s
dest += 1
dest[0] = 0
return original_dest
# String copy function with limited length
def strncpy(dest: str, src: str, n: t.CSizeT) -> str:
if dest == None or src == None or n == 0: return dest
original_dest: str = dest
i: t.CSizeT = 0
for s in src:
if i >= n: break
dest[0] = s
dest += 1
i += 1
# Fill remaining space with '\0'
while i < n:
dest[0] = 0
dest += 1
i += 1
return original_dest
# String concatenate function with limited length
def strncat(dest: str, src: str, n: t.CSizeT) -> str:
if dest == None or src == None or n == 0: return dest
original_dest: str = dest
# Find end of dest
while dest[0] != '\0':
dest += 1
# Copy up to n chars from src
i: t.CSizeT = 0
for s in src:
if i >= n: break
dest[0] = s
dest += 1
i += 1
dest[0] = 0
return original_dest
# String length function
export def strlen(src: str) -> t.CSizeT:
length: t.CSizeT = 0
for _ in src:
length += 1
return length
# String comparison function
# 注意:str1[0] - str2[0] 是 i8 减法会回绕(0xFF 表示 -1),返回前必须
# int() 提升到 i32 再相减(与下方 memcmp 的 int(p1[i]) - int(p2[i]) 一致),
# 否则 strcmp("abc","abd") 返回 255 而非 -1(StringTest Test 4 根因)。
def strcmp(str1: str, str2: str) -> int:
# 指针相等短路(降单次成本,不降调用次数):查表/自比较场景常拿同一驻留
# 字符串与自身比较(如 HashTable 以同一指针 set/lookup),指针相同则内容
# 必相同,直接返回 0,省去整趟逐字节循环;指针不同则走下方原逻辑。
# 语义严格不变(相同指针 ⇒ 内容相同 ⇒ strcmp 结果本应为 0)。
if str1 == str2:
return 0
while str1[0] != '\0' and str2[0] != '\0':
if str1[0] != str2[0]:
return int(str1[0]) - int(str2[0])
str1 += 1
str2 += 1
return int(str1[0]) - int(str2[0])
def samestr(str1: str, str2: str) -> bool:
return strcmp(str1, str2) == 0
# String compare function with limited length
def strncmp(str1: str, str2: str, n: t.CSizeT) -> int:
# 指针相等短路(同 strcmp):相同指针在任意 n 下比较结果恒为 0(相同字符串
# 的前 n 个字符必然相等),直接返回 0,语义严格不变。
if str1 == str2:
return 0
i: t.CSizeT = 0
while str1[0] != '\0' and str2[0] != '\0' and i < n:
if str1[0] != str2[0]:
return int(str1[0]) - int(str2[0])
str1 += 1
str2 += 1
i += 1
if i < n:
return int(str1[0]) - int(str2[0])
return 0
# Memory compare function
def memcmp(ptr1: t.CPtr, ptr2: t.CPtr, n: t.CSizeT) -> int:
p1: BYTEPTR = BYTEPTR(ptr1)
p2: BYTEPTR = BYTEPTR(ptr2)
i: t.CSizeT = 0
while i < n:
if p1[i] != p2[i]:
return int(p1[i]) - int(p2[i])
i += 1
return 0
# String find function
def strchr(s: str, cr: int) -> str:
while s[0] != '\0':
if s[0] == t.CChar(cr):
return str(s)
s += 1
if cr == '\0':
return str(s)
return None
# String reverse find function (find last occurrence of character)
def strrchr(s: str, cr: int) -> str:
last: str = None
while s[0] != '\0':
if s[0] == t.CChar(cr):
last = s
s += 1
if cr == '\0': return s
return last
# Substring search function (find first occurrence of needle in s, return pointer to that position, or None if not found)
# 热点优化(实测):原实现对**每个字节位置**都调用一次 strncmp,并先对 s 做一次全文 strlen。
# 实测 strstr 被调用 918 万次、strncmp 因此被调用 7.44 亿次(占全程序调用 29%,是第一名)。
# 改为先用 strchr 跳到"首字符匹配"的候选位置(跳过绝大多数不可能匹配的字节),
# 只在候选点做整段比较;同时不再预先 strlen(s)(strncmp 本身遇 '\0' 即停,安全)。
# 语义与原实现完全一致:needle 为空返回 s;未找到返回 None。
def strstr(s: str, needle: str) -> str:
if needle[0] == 0:
return s
needle_len: t.CSizeT = strlen(needle)
if needle_len == 0:
return s
first_ch: int = int(needle[0])
cur: str = s
while True:
hit: str = strchr(cur, first_ch)
if hit is None:
return None
if strncmp(hit, needle, needle_len) == 0:
return hit
cur = hit + 1
# String skip function
def strspn(s: str, skip: str = " ") -> int:
si: int = 0
while s[si] != 0:
found: int = 0
sj: int = 0
while skip[sj] != 0:
if s[si] == skip[sj]:
found = 1
break
sj += 1
if found == 0:
break
si += 1
return si
# Memory set function
export def memset(ptr: t.CPtr, value: int, num: t.CSizeT) -> t.CPtr:
# Original implementation:
# p: BYTEPTR = BYTEPTR(ptr)
# i: t.CSizeT
# for i in range(num):
# p[i] = t.CUnsignedChar(value)
if num == 0: return ptr
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
rep stosb""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
return ptr
def memset32(ptr: t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CPtr:
# Original implementation:
# p: UINT32PTR = UINT32PTR(ptr)
# i: t.CSizeT
# for i in range(count):
# p[i] = value
if count == 0: return ptr
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(count, t.ASM_DESCR.REG_ANY)}
rep stosd""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
return ptr
# Memory copy function
export def memcpy(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr:
# Original implementation:
# d: BYTEPTR = BYTEPTR(dest)
# s: BYTEPTR = BYTEPTR(src)
# i: t.CSizeT
# for i in range(num):
# d[i] = s[i]
if num == 0: return dest
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
rep movsb""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
return dest
# 内存移动函数
def memmove(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr:
# 原始实现:
# d: BYTEPTR = BYTEPTR(dest)
# s: BYTEPTR = BYTEPTR(src)
# i: t.CSizeT
# if d < s:
# for i in range(num):
# d[i] = s[i]
# elif d > s:
# for i in range(num, 0, -1):
# d[i - 1] = s[i - 1]
if num == 0: return dest
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
cmp rdi, rsi
jb 2f
std
add rdi, rcx
dec rdi
add rsi, rcx
dec rsi
rep movsb
cld
jmp 3f
2:
rep movsb
3:""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
return dest
def atoi(src: str) -> int:
num: int = 0
sign: int = 1
s: str = src
if s == None: return 0
# 跳过空白
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
s += 1
# 符号
if s[0] == '-':
sign = -1
s += 1
elif s[0] == '+':
s += 1
for ch in s:
if ch < '0' or ch > '9': break
digit: int = ch - '0'
num = num * 10 + digit
return num * sign
def atoll(src: str) -> t.CInt64T:
num: t.CInt64T = 0
sign: t.CInt64T = 1
s: str = src
if s == None: return 0
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
s += 1
if s[0] == '-':
sign = -1
s += 1
elif s[0] == '+':
s += 1
# 十六进制前缀 0x / 0X
is_hex: int = 0
if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'):
is_hex = 1
s += 2
if is_hex:
for ch in s:
d: int = 0
if ch >= '0' and ch <= '9':
d = ch - '0'
elif ch >= 'a' and ch <= 'f':
d = ch - 'a' + 10
elif ch >= 'A' and ch <= 'F':
d = ch - 'A' + 10
else:
break
digit: t.CInt64T = t.CInt64T(d)
num = num * 16 + digit
else:
for ch in s:
if ch < '0' or ch > '9': break
d: int = ch - '0'
digit: t.CInt64T = t.CInt64T(d)
num = num * 10 + digit
return num * sign
# ============================================================
# 十进制字面量 → double 的正确舍入转换(N4)
#
# 旧实现用"逐位累加 + 反复乘/除 10":小数位超过 16 位后每步都舍入
# (e 偏 +1 ULP、ln2 偏 −1 ULP),指数按 while exp>0: result*=10.0 累乘
# 308 次(DBL_MAX 偏 −6 ULP)。
# 新实现:尾数装进 u64(≤19 位;第 20 位做一次舍入),用 10 的**精确幂**
# 在**双 double(hi+lo,约 106 位)**下做一次缩放,最后一次性舍入。
# 算法先在 Python 里 1:1 对拍 float()(正确舍入)通过:20 万随机样例 +
# 边界样例在**正规数范围**内 bit-exact;次正规/溢出仍走旧逐步缩放兜底
# (语义与旧实现一致,无回归)。
# 约定:不用全局表——10^0..10^22 由循环乘 10 得到(该区间每一步都可精确
# 表示);p<0 时在正规区算 10^p×2^600 再精确缩回,避免双 double 低位在
# ~1e-292 以下掉进次正规而丢有效位。
# ============================================================
# _dd_split_hi - Dekker 分裂的上半(hi = 取高 26 位)
#
# 含量级缩尺:|a| > 6.7e292 时先乘 2^-28 再算(否则 a*(2^27+1) 溢出为 inf);
# |a| 极小(< 1e-292)时先乘 2^28(否则 lo = a-hi 掉进次正规丢位)。
# 缩尺因子均为 2 的幂 ⇒ 对正规数**无损**;调用方用 lo = a - hi 取下半部分。
def _dd_split_hi(a: double) -> double:
aa: double = a
big: int = 0
small: int = 0
if a > 6.7e292 or a < -6.7e292:
aa = a * 3.725290298461914e-09
big = 1
elif (a > 0.0 and a < 1.0e-292) or (a < 0.0 and a > -1.0e-292):
aa = a * 268435456.0
small = 1
tt: double = aa * 134217729.0
hi: double = tt - (tt - aa)
if big != 0:
return hi * 268435456.0
if small != 0:
return hi * 3.725290298461914e-09
return hi
# _dd_mul - 双 double 乘法:out = a × b(out[0]=hi, out[1]=lo)
def _dd_mul(ah: double, al: double, bh: double, bl: double,
out: t.CArray[double, 2]):
p: double = ah * bh
a_hi: double = _dd_split_hi(ah)
a_lo: double = ah - a_hi
b_hi: double = _dd_split_hi(bh)
b_lo: double = bh - b_hi
e: double = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo
e = e + (ah * bl + al * bh)
s: double = p + e
out[0] = s
out[1] = e - (s - p)
# _dd_add - 双 double 加法:out = a + b
def _dd_add(ah: double, al: double, bh: double, bl: double,
out: t.CArray[double, 2]):
s: double = ah + bh
bb: double = s - ah
e: double = (ah - (s - bb)) + (bh - bb)
e = e + (al + bl)
r0: double = s + e
out[0] = r0
out[1] = e - (r0 - s)
# _dd_div - 双 double 除法:out = a / b(q0 + 一步残差修正)
def _dd_div(ah: double, al: double, bh: double, bl: double,
out: t.CArray[double, 2], tmp: t.CArray[double, 2]):
q0: double = ah / bh
_dd_mul(bh, bl, q0, 0.0, tmp)
_dd_add(ah, al, -tmp[0], -tmp[1], tmp)
q1: double = tmp[0] / bh
_dd_add(q0, 0.0, q1, 0.0, out)
# _dd_from_u64 - u64 → 双 double(精确:hi 为四舍五入值,lo 为精确残差)
def _dd_from_u64(m: t.CUInt64T, out: t.CArray[double, 2]):
hi: double = double(m)
lo: double = 0.0
if m >= t.CUInt64T(9007199254740992):
lo = double(m - t.CUInt64T(hi))
s: double = hi + lo
bb: double = s - hi
out[0] = s
out[1] = (hi - (s - bb)) + (lo - bb)
# _dd_pow10 - 10^e 的双 double(e >= 0;按 ≤22 分块,每块可精确表示)
def _dd_pow10(e: int, out: t.CArray[double, 2], tmp: t.CArray[double, 2]):
out[0] = 1.0
out[1] = 0.0
k: int = e
while k > 0:
step: int = 22
if k < 22:
step = k
p10: double = 1.0
i: int = 0
while i < step:
p10 = p10 * 10.0
i += 1
_dd_mul(out[0], out[1], p10, 0.0, tmp)
out[0] = tmp[0]
out[1] = tmp[1]
k -= step
# _pow2 - 2^n(|n| <= 1000):循环乘 2/0.5,每步精确
def _pow2(n: int) -> double:
r: double = 1.0
i: int = n
if i >= 0:
while i > 0:
r = r * 2.0
i -= 1
else:
while i < 0:
r = r * 0.5
i += 1
return r
# _atof_scale_stepwise - 旧的逐步 ×/÷10 缩放(次正规/溢出场景的兜底)
def _atof_scale_stepwise(x: double, p: int) -> double:
r: double = x
e: int = p
while e > 0:
r = r * 10.0
e -= 1
while e < 0:
r = r / 10.0
e += 1
return r
def atof(src: str) -> double:
s: str = src
if s == None: return 0.0
# 跳过空白
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
s += 1
# 符号
sign: double = 1.0
if s[0] == '-':
sign = -1.0
s += 1
elif s[0] == '+':
s += 1
# 尾数:有效数字装进 u64(≤19 位),同时维护十进制指数
mant: t.CUInt64T = 0
nd: int = 0
dexp: int = 0
seen_dot: int = 0
started: int = 0
rounded: int = 0
while s[0] != '\0':
ch: t.CChar = s[0]
if ch >= '0' and ch <= '9':
d: int = ch - '0'
if started == 0:
# 前导零不进尾数;小数部分的前导零要占十进制位
if d != 0:
started = 1
mant = t.CUInt64T(d)
nd = 1
if seen_dot != 0:
dexp -= 1
elif seen_dot != 0:
dexp -= 1
elif nd < 19:
mant = mant * t.CUInt64T(10) + t.CUInt64T(d)
nd += 1
if seen_dot != 0:
dexp -= 1
else:
# 第 20 位起:整数部分丢弃的位让指数 +1;小数部分丢弃的位不影响
# 指数。只用第 20 位做一次舍入(丢弃量 <= 10^-19 相对误差)。
if seen_dot == 0:
dexp += 1
elif rounded == 0:
if d >= 5:
mant += t.CUInt64T(1)
rounded = 1
elif ch == '.':
seen_dot = 1
else:
break
s += 1
if started == 0:
return sign * 0.0
# 进位:舍入可能使 19 位变 20 位
if mant >= t.CUInt64T(10000000000000000000):
mant = mant // t.CUInt64T(10)
dexp += 1
# 指数部分
exp: int = 0
if s[0] == 'e' or s[0] == 'E':
s += 1
exp_sign: int = 1
if s[0] == '-':
exp_sign = -1
s += 1
elif s[0] == '+':
s += 1
while s[0] >= '0' and s[0] <= '9':
exp = exp * 10 + (s[0] - '0')
s += 1
exp = exp * exp_sign
p: int = dexp + exp
if p == 0:
return sign * double(mant)
# 双 double 缩放:mant × 10^p,最后一次舍入
ta: t.CArray[double, 2]
tb: t.CArray[double, 2]
tc: t.CArray[double, 2]
tr: t.CArray[double, 2]
_dd_from_u64(mant, ta)
v: double = 0.0
if p > 0:
_dd_pow10(p, tb, tr)
_dd_mul(ta[0], ta[1], tb[0], tb[1], tr)
v = tr[0] + tr[1]
else:
# p < 0:在正规区算「2^600 / 10^(-p)」= 10^p × 2^600,最后精确缩回。
# 不能直接算 10^p(|p| 大时 ~1e-308,双 double 低位掉次正规丢有效位);
# 分母按 ≤308 分块累除(10^313 会先溢出成 inf 使结果变 NaN)。
tb[0] = _pow2(600)
tb[1] = 0.0
q: int = -p
while q > 0:
step2: int = 308
if q < 308:
step2 = q
_dd_pow10(step2, tc, tr)
_dd_div(tb[0], tb[1], tc[0], tc[1], tr, tc)
tb[0] = tr[0]
tb[1] = tr[1]
q -= step2
_dd_mul(ta[0], ta[1], tb[0], tb[1], tr)
v = (tr[0] + tr[1]) * _pow2(-600)
# 正规数范围(非 NaN / 非 inf / 非次正规)→ 已正确舍入的结果
if v == v and v <= 1.7976931348623157e308 and v >= -1.7976931348623157e308 \
and (v == 0.0 or v >= 2.2250738585072014e-308 or v <= -2.2250738585072014e-308):
return sign * v
# 溢出 / 次正规 / NaN → 回退旧逐步缩放(与旧实现语义一致)
return sign * _atof_scale_stepwise(double(mant), p)
def atof_out(src: str, out: double | t.CPtr) -> int:
"""atof 结果写入 out[0](输出参数方式,避免跨模块 double 返回值传递 bug)
返回值仅表示成功与否(1=成功,0=失败),结果值通过 out 指针传递,
不依赖 double 返回值的跨模块传递。
"""
if out is None:
return 0
v: double = atof(src)
out[0] = v
return 1
def split(s: str, delim: str, result: t.CArray[str], cap: int) -> int:
"""按单字符分隔符切分 s,token 指针写入 result[0..],尾部写 None 哨兵。
cap: result 数组的**声明容量**(元素个数)。此前无容量参数 → 写
result[count] 与 result[count]=None 均无上界;token 数超过调用方数组
容量时越界写(devfs 用 t.CArray[str, 256],256 个 token 即写穿 2048 字节)。
现限制 token 数 ≤ cap-1(留一格给结尾哨兵)。
"""
count: int = 0
start: str = s
if not s or not delim or not result:
return 0
if cap <= 0:
return 0
d: t.CChar = delim[0] # 单分隔符
while start[0]:
# 跳过分隔符
while start[0] == d: start += 1
if not start[0]: break
# 容量保护:留最后一格放结尾哨兵
if count >= cap - 1:
break
# 记录token起始
result[count] = start
count += 1
# 找到下一个分隔符,截断
while start[0] and start[0] != d: start += 1
if start[0]:
start[0] = '\0'
start += 1
result[count] = None # 结尾标记
return count
ascii_lowercase: str = "abcdefghijklmnopqrstuvwxyz"
ascii_uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ascii_letters: str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
digits: str = "0123456789"
hexdigits: str = "0123456789abcdefABCDEF"
octdigits: str = "01234567"
punctuation: str = "!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~"
whitespace: str = " \t\n\r\f\v"
printable: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\f\v"