Files
cKit/Foundation/c_StringView.c
T

208 lines
6.5 KiB
C
Raw Normal View History

2026-08-30 12:59:42 +08:00
#include <c_StringView.h>
#include <limits.h>
#include <stdlib.h>
char* c_StringView_ToCStr(const c_StringView_t* self, char* buf, c_size_t buf_size) {
// 边界防御:缓冲区必须有效且大小至少为 1(以便容纳 \0)
if (!buf || buf_size == 0) {
return NULL;
}
// 边界防御:如果 self 为空或底层无数据,直接赋予空字符串并返回
if (!self || self->size == 0 || !self->str) {
buf[0] = '\0';
return buf;
}
// 计算实际能够安全拷贝的数据字节数(预留 1 字节给 '\0'
c_size_t max_copy = buf_size - 1;
c_size_t actual_copy = (self->size < max_copy) ? self->size : max_copy;
// 执行内存拷贝(允许中间包含 \0 字符的特殊视图)
if (actual_copy > 0) {
memcpy(buf, self->str, actual_copy);
}
// 在缓冲区末尾强行补上标准传统 C 字符串的结束符
buf[actual_copy] = '\0';
return buf;
}
unsigned long c_StringView_ToUL(const c_StringView_t* self, const char** endptr, int base) {
if (!self || self->size == 0 || !self->str) {
if (endptr) *endptr = (self ? self->str : NULL);
return 0;
}
const char* start = self->str;
const char* end = self->str + self->size;
// 1. 跳过前导空白字符
while (start < end && isspace((unsigned char)*start)) {
start++;
}
// 如果全是空格,直接返回 0
if (start >= end) {
if (endptr) *endptr = self->str;
return 0;
}
// 2. 处理正负号 (虽然是无符号转码,标准 strtoul 仍允许 '-' 号并对其求补码)
int negate = 0;
if (*start == '+') {
start++;
} else if (*start == '-') {
negate = 1;
start++;
}
// 3. 自动识别进制 (Base == 0) 或校验 16 进制前缀
if (base == 0) {
if (start + 1 < end && *start == '0' && (start[1] == 'x' || start[1] == 'X')) {
base = 16;
start += 2;
} else if (start < end && *start == '0') {
base = 8;
start++;
} else {
base = 10;
}
} else if (base == 16) {
// 如果显式指定了16进制,允许略过 0x/0X 前缀
if (start + 1 < end && *start == '0' && (start[1] == 'x' || start[1] == 'X')) {
start += 2;
}
}
unsigned long result = 0;
unsigned long cutoff = ULONG_MAX / (unsigned long)base;
int cutlim = ULONG_MAX % (unsigned long)base;
int any_digits = 0;
int overflow = 0;
// 4. 核心解析循环,严格受限于底层 View 的 End 边界
while (start < end) {
unsigned char c = (unsigned char)*start;
int digit;
if (isdigit(c)) {
digit = c - '0';
} else if (isalpha(c)) {
digit = tolower(c) - 'a' + 10;
} else {
break; // 遇到非法字符,退出解析
}
if (digit >= base) {
break; // 超过当前进制最大范围,退出解析
}
any_digits = 1;
// 检查溢出
if (overflow || result > cutoff || (result == cutoff && digit > cutlim)) {
overflow = 1;
} else {
result = result * (unsigned long)base + (unsigned long)digit;
}
start++;
}
// 5. 组装返回值与写回结束指针
if (endptr) {
*endptr = any_digits ? start : self->str;
}
if (overflow) {
return ULONG_MAX;
}
return negate ? (unsigned long)(-(long)result) : result;
}
double c_StringView_ToDouble(const c_StringView_t* self, const char** endptr) {
if (!self || self->size == 0 || !self->str) {
if (endptr) *endptr = (self ? self->str : NULL);
return 0.0;
}
// 1. 跳过前导空白字符
const char* start = self->str;
const char* end = self->str + self->size;
while (start < end && isspace((unsigned char)*start)) {
start++;
}
// 计算实际可能包含有效浮点数据的长度
size_t active_len = end - start;
if (active_len == 0) {
if (endptr) *endptr = self->str;
return 0.0;
}
// 2. 核心避坑:由于 strtod 需要 \0 结尾,但 StringView 并没有。
// 我们在栈上开辟一个小缓冲区(256字节足够容纳任何有效的 IEEE 754 浮点数字符串,包括极其冗长的科学计数法)。
// 这避免了 malloc 带来的堆内存分配开销,同时保证了线程安全。
char local_buf[256];
size_t copy_len = (active_len < sizeof(local_buf) - 1) ? active_len : (sizeof(local_buf) - 1);
memcpy(local_buf, start, copy_len);
local_buf[copy_len] = '\0';
// 3. 调用标准库进行高精度解析(能完美处理 NaN、Inf 以及复杂的科学计数法扩展)
char* local_endptr = NULL;
double result = strtod(local_buf, &local_endptr);
// 4. 将本地缓冲区的相对终止偏移量映射回原始的 StringView 真实指针
if (endptr) {
if (local_endptr == local_buf) {
// 如果 strtod 完全未能识别出任何数字
*endptr = self->str;
} else {
ptrdiff_t parsed_offset = local_endptr - local_buf;
*endptr = start + parsed_offset;
}
}
return result;
}
c_index_t c_StringView_FindStr(const c_StringView_t* self, const c_size_t start_pos, const c_StringView_t* needle) {
// 1. 边界与有效性防御
if (!self || !self->str || !needle || !needle->str) {
return -1;
}
// 子串为空时,根据标准 C/C++ 行为,默认在有效起点处直接匹配成功
if (needle->size == 0) {
return (start_pos <= self->size) ? (c_index_t)start_pos : -1;
}
// 起始位置越界,或者子串长度已经超过了可供查找的剩余主串长度
if (start_pos >= self->size || (self->size - start_pos) < needle->size) {
return -1;
}
// 2. 核心搜索算法:在主串死边界内进行滑窗 memcmp 匹配
c_size_t max_search_idx = self->size - needle->size;
c_size_t needle_len = needle->size;
const char* haystack = self->str;
for (c_size_t i = start_pos; i <= max_search_idx; i++) {
// 第一步快筛:首字符匹配时再执行深度 memcmp,极大提升非匹配时滑窗的执行效率
if (haystack[i] == needle->str[0]) {
if (memcmp(haystack + i, needle->str, needle_len) == 0) {
return (c_index_t)i; // 找到匹配,返回主串对应下标
}
}
}
return -1; // 遍历完毕,未找到匹配项
}