#ifndef INCLUDED_C_STRINGVIEW_H #define INCLUDED_C_STRINGVIEW_H #ifndef INCLUDED_C_TYPES_H #include #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*/