Files
cKit/Foundation/c_StringView.h
T

166 lines
5.7 KiB
C
Raw Normal View History

2026-08-30 12:59:42 +08:00
#ifndef INCLUDED_C_STRINGVIEW_H
#define INCLUDED_C_STRINGVIEW_H
#ifndef INCLUDED_C_TYPES_H
#include <c_Types.h>
#endif /*INCLUDED_C_TYPES_H*/
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
typedef struct {
const char* str;
c_size_t size;
}c_StringView_t;
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
C_STATIC_FORCE_INLINE
c_StringView_t c_StringView_FromCStr(const char* str) {
c_StringView_t result;
result.str = str;
result.size = str?strlen(str):0;
return result;
}
C_STATIC_FORCE_INLINE
c_StringView_t c_StringView_FromParts(const char* str, c_size_t len) {
c_StringView_t result;
result.str = str;
result.size = len;
return result;
}
C_STATIC_FORCE_INLINE
c_StringView_t c_StringView_Sub(const c_StringView_t* self, c_size_t start, c_size_t len) {
c_StringView_t result={0};
if (start < self->size) {
result.str = self->str + start;
result.size = ((start + len) <= self->size)?len:(self->size - start);
}
return result;
}
C_STATIC_FORCE_INLINE
c_StringView_t c_StringView_RemovePrefix(const c_StringView_t* self, c_size_t n) {
if (n >= self->size) {
return (c_StringView_t){NULL, 0};
}
return (c_StringView_t){self->str + n, self->size - n};
}
C_STATIC_FORCE_INLINE
c_StringView_t c_StringView_Trim(c_StringView_t* self) {
c_size_t start = 0;
c_size_t end = self->size;
while (start < end && isspace((unsigned char)self->str[start])) {
start++;
}
while (end > start && isspace((unsigned char)self->str[end - 1])) {
end--;
}
return (c_StringView_t){ self->str + start, end - start };
}
C_STATIC_FORCE_INLINE
int c_StringView_Cmp(c_StringView_t* sv1, c_StringView_t* sv2) {
c_size_t min_len = (sv1->size < sv2->size) ? sv1->size : sv2->size;
int cmp = memcmp(sv1->str, sv2->str, min_len);
if (cmp != 0) return cmp;
if (sv1->size < sv2->size) return -1;
if (sv1->size > sv2->size) return 1;
return 0;
}
C_STATIC_FORCE_INLINE
bool c_StringView_IsEq(c_StringView_t* sv1, c_StringView_t* sv2) {
if (sv1->size != sv2->size) return false;
if (sv1->str == sv2->str) return true;
return memcmp(sv1->str, sv2->str, sv1->size) == 0;
}
C_STATIC_FORCE_INLINE
bool c_StringView_HasPrefix(c_StringView_t* self, c_StringView_t* prefix) {
if (self->size < prefix->size) return false;
return memcmp(self->str, prefix->str, prefix->size) == 0;
}
C_STATIC_FORCE_INLINE
bool c_StringView_HasSuffix(c_StringView_t* self, c_StringView_t* suffix) {
if (self->size < suffix->size) return false;
const char *start = self->str + (self->size - suffix->size);
return memcmp(start, suffix->str, suffix->size) == 0;
}
C_STATIC_FORCE_INLINE
c_index_t c_StringView_FindChar(const c_StringView_t* self, const c_size_t start_pos, const char c) {
if (start_pos >= self->size) return -1;
for (c_size_t i = start_pos; i < self->size; i++) {
if (self->str[i] == c) {
return (c_index_t)i;
}
}
return -1;
}
C_STATIC_FORCE_INLINE
bool c_StringView_Split(c_StringView_t * self, const char delim, c_StringView_t* left, c_StringView_t* right) {
const c_index_t idx = c_StringView_FindChar(self, 0, delim);
if (idx == -1) {
if (left) *left = *self;
if (right) *right = (c_StringView_t){ NULL, 0 };
return false;
}
if (left) *left = c_StringView_Sub(self, 0, idx);
if (right) *right = c_StringView_Sub(self, idx + 1, self->size - idx - 1);
return true;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief 将 StringView 转换为传统的以 \0 结尾的 C 字符串(输出到外部缓冲区)
*
* @param self 指向待转换的 StringView 的指针
* @param buf 用户提供的外部字符缓冲区指针
* @param buf_size 外部缓冲区的大小(字节数)
* @return char* 返回传入的 buf 指针。若输入参数非法或 buf_size 为 0,则返回 NULL
*/
char* c_StringView_ToCStr(const c_StringView_t* self, char* buf, c_size_t buf_size);
/**
* @brief 将 StringView 转换为 unsigned long 整数 (模仿 strtoul)
*
* @param self 指向待解析的 StringView 的指针
* @param endptr 可选参数。若不为 NULL,则用于存储解析终止处的字符指针
* @param base 进制基数 (0 或 2-36)。为 0 时自动识别 0x (16进制), 0 (8进制), 否则默认10进制
* @return unsigned long 解析出的无符号长整数。若发生溢出返回 ULONG_MAX
*/
unsigned long c_StringView_ToUL(const c_StringView_t* self, const char** endptr, int base);
/**
* @brief 将 StringView 转换为高精度双精度浮点数 (模仿 strtod)
*
* @param self 指向待解析的 StringView 的指针
* @param endptr 可选参数。若不为 NULL,则用于存储解析终止处的字符指针
* @return double 解析出的浮点数。如果发生严重溢出返回 HUGE_VAL 或 -HUGE_VAL
*/
double c_StringView_ToDouble(const c_StringView_t* self, const char** endptr);
/**
* @brief 在主 StringView 中查找指定子 StringView 首次出现的位置
*
* @param self 指向主 StringView 的指针
* @param start_pos 开始查找的起始下标位置
* @param needle 指向待查找子 StringView 的指针
* @return c_index_t 找到时返回匹配子串在主串中的起始下标(相对 self->str);未找到或参数非法时返回 -1
*/
c_index_t c_StringView_FindStr(const c_StringView_t* self, const c_size_t start_pos, const c_StringView_t* needle);
#endif /*INCLUDED_C_STRINGVIEW_H*/