Files
2026-08-30 22:24:45 +08:00

208 lines
6.5 KiB
C
Raw Permalink 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.
#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 ((c_size_t)(end - start) >= 2 && *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 ((c_size_t)(end - start) >= 2 && *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; // 遍历完毕,未找到匹配项
}