mirror of
https://gitee.com/apaki/unicstl.git
synced 2026-05-28 22:54:19 +08:00
681 lines
16 KiB
C
681 lines
16 KiB
C
/**
|
|
* @file ustring.c
|
|
* @author wenjf (Orig5826@163.com)
|
|
* @brief
|
|
* @version 0.1
|
|
* @date 2026-05-17
|
|
*
|
|
* @copyright Copyright (c) 2026
|
|
*
|
|
*/
|
|
#include "ustring.h"
|
|
#include "algo.h"
|
|
#include <ctype.h>
|
|
|
|
static const char null_char = '\0';
|
|
|
|
static size_t ustring_len(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->size(self->_alist) - 1;
|
|
}
|
|
|
|
static size_t ustring_capacity(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->capacity(self->_alist);
|
|
}
|
|
|
|
static bool ustring_empty(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->empty(self->_alist);
|
|
}
|
|
|
|
static bool ustring_full(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->full(self->_alist);
|
|
}
|
|
|
|
static bool ustring_clear(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->clear(self->_alist);
|
|
}
|
|
|
|
static void ustring_destory(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
if (self->_alist != NULL)
|
|
{
|
|
arraylist_free(&self->_alist);
|
|
}
|
|
}
|
|
|
|
static void ustring_print(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
self->_alist->print_obj = self->print_obj;
|
|
self->_alist->print(self->_alist);
|
|
}
|
|
|
|
static bool ustring_reserve(struct _ustring *self, size_t capacity)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->reserve(self->_alist, capacity);
|
|
}
|
|
|
|
static bool ustring_resize(struct _ustring *self, size_t size)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
arraylist_t alist = self->_alist;
|
|
if (!alist->resize(alist, size + 1))
|
|
{
|
|
false;
|
|
}
|
|
alist->set(alist, size, &null_char);
|
|
return true;
|
|
}
|
|
|
|
static bool ustring_insert(struct _ustring *self, size_t index, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return true;
|
|
}
|
|
|
|
static bool ustring_remove(struct _ustring *self, uview_t oldstr)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return true;
|
|
}
|
|
|
|
static bool ustring_pop(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->pop(self->_alist, NULL);
|
|
}
|
|
|
|
static bool ustring_append(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
arraylist_t alist = self->_alist;
|
|
alist->pop(alist, NULL); // pop '\0' first
|
|
for (size_t i = 0; i < v.len; i++)
|
|
{
|
|
if (!alist->append(alist, &v.str[i]))
|
|
{
|
|
log_error("ustring_append error");
|
|
return false;
|
|
}
|
|
}
|
|
if (!alist->append(alist, &null_char))
|
|
{
|
|
log_error("append '\0' error");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool ustring_set(struct _ustring *self, size_t index, const char c)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->set(self->_alist, index, &c);
|
|
}
|
|
|
|
static bool ustring_get(struct _ustring *self, size_t index, char *c)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->get(self->_alist, index, &c);
|
|
}
|
|
|
|
static const char* ustring_at(struct _ustring *self, size_t index)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->at(self->_alist, index);
|
|
}
|
|
|
|
bool ustring_iter_hasnext(struct _iterator *iter)
|
|
{
|
|
unicstl_assert(iter != NULL);
|
|
unicstl_assert(iter->_container != NULL);
|
|
|
|
ustring_t self = (ustring_t)iter->_container;
|
|
|
|
if (iter->_order == LINEAR_FORWARD)
|
|
{
|
|
if (iter->_index >= self->len(self))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (iter->_index == 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const void *ustring_iter_next(struct _iterator *iter)
|
|
{
|
|
unicstl_assert(iter != NULL);
|
|
unicstl_assert(iter->_container != NULL);
|
|
|
|
ustring_t self = (ustring_t)iter->_container;
|
|
|
|
size_t index = iter->_index;
|
|
if (iter->_order == LINEAR_FORWARD)
|
|
{
|
|
iter->_index++;
|
|
}
|
|
else
|
|
{
|
|
iter->_index = iter->_index - 1;
|
|
}
|
|
return self->_alist->at(self->_alist, index);
|
|
}
|
|
|
|
iterator_t ustring_iter(struct _ustring *self, linear_order_t order)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
iterator_t iter = &self->_iter;
|
|
|
|
iter->_container = self;
|
|
iter->_index = 0;
|
|
iter->_order = order;
|
|
if (iter->_order == LINEAR_FORWARD)
|
|
{
|
|
iter->_index = 0;
|
|
}
|
|
else
|
|
{
|
|
iter->_index = self->len(self) - 1;
|
|
}
|
|
|
|
iter->hasnext = ustring_iter_hasnext;
|
|
iter->next = ustring_iter_next;
|
|
return iter;
|
|
}
|
|
|
|
static size_t ustring_index(struct _ustring *self, const void *obj)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->search(self, obj);
|
|
}
|
|
|
|
static bool ustring_contains(struct _ustring *self, const void *obj)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->search(self, obj) != (size_t)-1;
|
|
}
|
|
|
|
static bool darry_sort(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->sort(self->_alist);
|
|
}
|
|
|
|
static size_t darry_search(struct _ustring *self, const void *obj)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->search(self->_alist, obj);
|
|
}
|
|
|
|
static size_t darry_count(struct _ustring *self, const void *obj)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
return self->_alist->count(self->_alist, obj);
|
|
}
|
|
|
|
bool ustring_isdigit(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isdigit(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
bool ustring_isalpha(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isalpha(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_isalnum(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isalnum(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_isspace(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isspace(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_islower(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!islower(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_isupper(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isupper(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_iscntrl(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!iscntrl(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_isprint(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isprint(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_ispunct(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!ispunct(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_isgraph(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
if (!isgraph(*(char *)self->_alist->at(self->_alist, i)))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const char *ustring_cstr(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
arraylist_t alist = self->_alist;
|
|
return (const char *)alist->_darray->obj;
|
|
}
|
|
|
|
bool ustring_tolower(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
*(char *)self->_alist->at(self->_alist, i) = tolower(*(char *)self->_alist->at(self->_alist, i));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_toupper(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
for (size_t i = 0; i < self->len(self); i++)
|
|
{
|
|
*(char *)self->_alist->at(self->_alist, i) = toupper(*(char *)self->_alist->at(self->_alist, i));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ustring_reverse(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
arraylist_t da = self->_alist;
|
|
char temp = 0;
|
|
for (size_t i = 0; i < self->len(self) / 2; i++)
|
|
{
|
|
size_t j = self->len(self) - i - 1;
|
|
da->get(da, i, &temp);
|
|
da->set(da, i, da->at(da, j));
|
|
da->set(da, j, da->at(da, i));
|
|
}
|
|
}
|
|
|
|
static bool ustring_strip(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->strip_right(self) && self->strip_left(self);
|
|
}
|
|
|
|
static bool ustring_strip_left(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
arraylist_t da = self->_alist;
|
|
log_debug("strip_left: %ld", da->size(da));
|
|
size_t i = 0;
|
|
for (i = 0; i < da->size(da); i++)
|
|
{
|
|
if (!isspace(*(char *)da->at(da, i)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
da->erase(da, 0, i);
|
|
return true;
|
|
}
|
|
|
|
static bool ustring_strip_right(struct _ustring *self)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
unicstl_assert(self->_alist != NULL);
|
|
arraylist_t da = self->_alist;
|
|
size_t i = 0;
|
|
for (i = self->len(self) - 1; i >= 0; i--)
|
|
{
|
|
if (!isspace(*(char *)da->at(da, i)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
self->resize(self, i + 1);
|
|
return true;
|
|
}
|
|
|
|
int ustring_cmp(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
// size_t min = self->len(self) < v.len ? self->len(self) : v.len;
|
|
// for (size_t i = 0; i < min; i++)
|
|
// {
|
|
// const char *a = (const char *)self->at(self, i);
|
|
// if (*a != v.str[i])
|
|
// {
|
|
// return *(char*)self->at(self, i) - v.str[i];
|
|
// }
|
|
// }
|
|
log_debug("self[%d]:%s, v.str[%d]:%s", self->len(self), self->at(self, 0), v.len, v.str);
|
|
|
|
size_t max = self->len(self) > v.len ? self->len(self) : v.len;
|
|
return strncmp(self->at(self, 0), v.str, max);
|
|
}
|
|
|
|
int ustring_eq(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->cmp(self, v) == 0;
|
|
}
|
|
|
|
int ustring_ne(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->cmp(self, v) != 0;
|
|
}
|
|
|
|
int ustring_lt(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->cmp(self, v) < 0;
|
|
}
|
|
|
|
int ustring_le(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->cmp(self, v) <= 0;
|
|
}
|
|
|
|
int ustring_gt(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->cmp(self, v) > 0;
|
|
}
|
|
|
|
int ustring_ge(struct _ustring *self, uview_t v)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
return self->cmp(self, v) >= 0;
|
|
}
|
|
|
|
static bool ustring_init(struct _ustring *self, uview_t view, bool is_view)
|
|
{
|
|
unicstl_assert(self != NULL);
|
|
|
|
// -------------------- private --------------------
|
|
self->_sorted = false;
|
|
|
|
self->_alist = NULL;
|
|
self->_destory = ustring_destory;
|
|
|
|
self->is_view = is_view;
|
|
|
|
// -------------------- public --------------------
|
|
// kernel
|
|
self->insert = ustring_insert;
|
|
self->remove = ustring_remove;
|
|
self->append = ustring_append;
|
|
|
|
self->set = ustring_set;
|
|
self->get = ustring_get;
|
|
self->at = ustring_at;
|
|
|
|
// base
|
|
self->reserve = ustring_reserve;
|
|
self->resize = ustring_resize;
|
|
self->len = ustring_len;
|
|
self->capacity = ustring_capacity;
|
|
self->empty = ustring_empty;
|
|
self->full = ustring_full;
|
|
self->clear = ustring_clear;
|
|
|
|
// iter
|
|
self->iter = ustring_iter;
|
|
|
|
// sort and search
|
|
self->index = ustring_index;
|
|
self->contains = ustring_contains;
|
|
self->sort = darry_sort;
|
|
self->search = darry_search;
|
|
|
|
// string
|
|
self->isdigit = ustring_isdigit;
|
|
self->isalpha = ustring_isalpha;
|
|
self->isalnum = ustring_isalnum;
|
|
self->isspace = ustring_isspace;
|
|
self->islower = ustring_islower;
|
|
self->isupper = ustring_isupper;
|
|
self->iscntrl = ustring_iscntrl;
|
|
self->isprint = ustring_isprint;
|
|
self->ispunct = ustring_ispunct;
|
|
self->isgraph = ustring_isgraph;
|
|
self->cstr = ustring_cstr;
|
|
self->tolower = ustring_tolower;
|
|
self->toupper = ustring_toupper;
|
|
self->reverse = ustring_reverse;
|
|
|
|
// strip
|
|
self->strip = ustring_strip;
|
|
self->strip_left = ustring_strip_left;
|
|
self->strip_right = ustring_strip_right;
|
|
|
|
self->eq = ustring_eq;
|
|
self->ne = ustring_ne;
|
|
self->lt = ustring_lt;
|
|
self->le = ustring_le;
|
|
self->gt = ustring_gt;
|
|
self->ge = ustring_ge;
|
|
self->cmp = ustring_cmp;
|
|
|
|
// -------------------- default --------------------
|
|
self->print_obj = uprint_char;
|
|
|
|
// -------------------- debug --------------------
|
|
self->print = ustring_print;
|
|
|
|
// -------------------- malloc --------------------
|
|
self->_alist = arraylist_new(sizeof(char), view.len + 1);
|
|
if (self->_alist == NULL)
|
|
{
|
|
log_warn("malloc darray failed!");
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < view.len; i++)
|
|
{
|
|
if (!self->_alist->append(self->_alist, &view.str[i]))
|
|
{
|
|
log_error("append failed!");
|
|
return false;
|
|
}
|
|
}
|
|
if (!self->_alist->append(self->_alist, &null_char))
|
|
{
|
|
log_error("append '\0' failed!");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ustring_t ustring_new(uview_t view)
|
|
{
|
|
struct _ustring *ustring = NULL;
|
|
ustring = (struct _ustring *)unicstl_malloc(sizeof(struct _ustring));
|
|
if (ustring == NULL)
|
|
{
|
|
log_warn("ustring malloc failed!");
|
|
return NULL;
|
|
}
|
|
|
|
if (ustring_init(ustring, view, false) != true)
|
|
{
|
|
log_warn("ustring init failed!");
|
|
unicstl_free(ustring);
|
|
return NULL;
|
|
}
|
|
return ustring;
|
|
}
|
|
|
|
void ustring_free(ustring_t *ustring)
|
|
{
|
|
if (ustring != NULL && *ustring != NULL)
|
|
{
|
|
if ((*ustring)->_destory != NULL)
|
|
{
|
|
(*ustring)->_destory((*ustring));
|
|
}
|
|
unicstl_free(*ustring);
|
|
*ustring = NULL;
|
|
}
|
|
}
|
|
|
|
ustring_t ustring_view(uview_t view)
|
|
{
|
|
log_error("TODO: implement ustring_view()");
|
|
return NULL;
|
|
|
|
struct _ustring *ustring = NULL;
|
|
ustring = (struct _ustring *)unicstl_malloc(sizeof(struct _ustring));
|
|
if (ustring == NULL)
|
|
{
|
|
log_warn("ustring malloc failed!");
|
|
return NULL;
|
|
}
|
|
|
|
if (ustring_init(ustring, view, true) != true)
|
|
{
|
|
log_warn("ustring init failed!");
|
|
unicstl_free(ustring);
|
|
return NULL;
|
|
}
|
|
return ustring;
|
|
}
|