Fix guf_str bugs and add tests
This commit is contained in:
parent
0910ee4bd8
commit
e98dc3b91e
334
src/guf_str.h
334
src/guf_str.h
@ -84,10 +84,9 @@ GUF_STR_KWRDS guf_str_view guf_str_view_trim_left_ascii(guf_str_view sv);
|
||||
GUF_STR_KWRDS guf_str_view guf_str_next_tok(guf_str_view *input, const guf_str_view *delims, ptrdiff_t num_delims, const guf_str_view *preserved_delims, ptrdiff_t num_preserved_delims);
|
||||
|
||||
// guf_str:
|
||||
|
||||
// DONE:
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_init(guf_str *str, guf_str_view str_view, guf_allocator *alloc, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_init(guf_str *str, guf_str_view str_view, guf_allocator *alloc);
|
||||
GUF_STR_KWRDS guf_str *guf_str_init_empty(guf_str *str, guf_allocator *alloc);
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_init_from_cstr(guf_str *str, const char* c_str, guf_allocator *alloc, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_init_from_cstr(guf_str *str, const char* c_str, guf_allocator *alloc);
|
||||
@ -98,11 +97,24 @@ GUF_STR_KWRDS guf_str guf_str_new(guf_str_view str_view, guf_allocator *alloc);
|
||||
GUF_STR_KWRDS void guf_str_free(guf_str *str, void *ctx);
|
||||
GUF_STR_KWRDS guf_str *guf_str_copy(guf_str *dst, const guf_str *src, void *ctx);
|
||||
GUF_STR_KWRDS guf_str *guf_str_move(guf_str *dst, guf_str *src, void *ctx);
|
||||
|
||||
GUF_STR_KWRDS bool guf_str_equal(const guf_str *a, const guf_str *b);
|
||||
GUF_STR_KWRDS int guf_str_cmp(const guf_str *a, const guf_str *b);
|
||||
|
||||
// DONE:
|
||||
// Reserve at least min_capacity characters (excluding the null-terminator) (try to double the current capacity first; if that's not at least min_capacity, set the new capacity to min_capacity instead).
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t min_capacity, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_reserve(guf_str *str, ptrdiff_t min_capacity);
|
||||
// Shrink the capacity of the string so it does not waste space (short-string-optimisation will be applied if the new capacity <= GUF_STR_SSO_BUF_CAP)
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_shrink_to_fit(guf_str *str, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_shrink_to_fit(guf_str *str);
|
||||
|
||||
// Set the contents of str to the given string view (mutating str) -> return the mutated str
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_set(guf_str *str, guf_str_view str_view, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_set(guf_str *str, guf_str_view str_view);
|
||||
|
||||
// Return a view of the string.
|
||||
GUF_STR_KWRDS guf_str_view guf_str_to_view(const guf_str *str);
|
||||
|
||||
// Return a non-const pointer to the character at the specified index of str (if possible)
|
||||
GUF_STR_KWRDS char *guf_str_try_at(guf_str *str, ptrdiff_t idx, guf_err *err);
|
||||
GUF_STR_KWRDS char *guf_str_at(guf_str *str, ptrdiff_t idx);
|
||||
GUF_STR_KWRDS char *guf_str_try_back(guf_str *str, guf_err *err);
|
||||
@ -110,6 +122,7 @@ GUF_STR_KWRDS char *guf_str_back(guf_str *str);
|
||||
GUF_STR_KWRDS char *guf_str_try_front(guf_str *str, guf_err *err);
|
||||
GUF_STR_KWRDS char *guf_str_front(guf_str *str);
|
||||
|
||||
// Return a copy of the char at the specified index of str (if possible)
|
||||
GUF_STR_KWRDS char guf_str_try_at_cpy(const guf_str *str, ptrdiff_t idx, guf_err *err);
|
||||
GUF_STR_KWRDS char guf_str_at_cpy(const guf_str *str, ptrdiff_t idx);
|
||||
GUF_STR_KWRDS char guf_str_try_back_cpy(const guf_str *str, guf_err *err);
|
||||
@ -117,45 +130,42 @@ GUF_STR_KWRDS char guf_str_back_cpy(const guf_str *str);
|
||||
GUF_STR_KWRDS char guf_str_try_front_cpy(const guf_str *str, guf_err *err);
|
||||
GUF_STR_KWRDS char guf_str_front_cpy(const guf_str *str);
|
||||
|
||||
// DONE:
|
||||
// Make substring in-place (constant time if pos == 0, otherwise copying count chars to the beginning of the str, i.e. linear time)
|
||||
/*
|
||||
Turn str into the substring in range [pos, pos + count) (mutating str) -> return the mutated str
|
||||
(Constant time if pos == 0, otherwise copying count chars to the beginning of the str, i.e. linear time.)
|
||||
NOTE: To make a substring-copy (instead of mutating str), create a guf_str_view of str and use guf_str_view_substr
|
||||
*/
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_substr(guf_str *str, ptrdiff_t pos, ptrdiff_t count, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_substr(guf_str *str, ptrdiff_t pos, ptrdiff_t count);
|
||||
|
||||
// TODO:
|
||||
// Remove the last character from str if possible (mutating str) -> return the popped char
|
||||
GUF_STR_KWRDS char guf_str_try_pop_back(guf_str *str, guf_err *err);
|
||||
GUF_STR_KWRDS char guf_str_pop_back(guf_str *str);
|
||||
GUF_STR_KWRDS char guf_str_pop_front(guf_str *str);
|
||||
|
||||
// DONE:
|
||||
// Append a char to str (n times; times must be >= 0) (mutating str) -> return the mutated str
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_append_char(guf_str *str, char c, ptrdiff_t times, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_append_char(guf_str *str, char c, ptrdiff_t times);
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_append_one_char(guf_str *str, char c, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_append_one_char(guf_str *str, char c);
|
||||
|
||||
// Append str_view to str (mutating str) -> return the mutated str
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_append(guf_str *str, guf_str_view sv, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_append(guf_str *str, guf_str_view sv);
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_append_cstr(guf_str *str, const char *c_str, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_append_cstr(guf_str *str, const char *c_str);
|
||||
|
||||
// DONE:
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t min_capacity, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_reserve(guf_str *str, ptrdiff_t min_capacity);
|
||||
|
||||
// TODO:
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_shrink_to_fit(guf_str *str, guf_err *err);
|
||||
GUF_STR_KWRDS guf_str *guf_str_shrink_to_fit(guf_str *str);
|
||||
|
||||
// DONE:
|
||||
// Return a pointer to the null-terminated char array representing the string (works like std::string::c_str in C++)
|
||||
GUF_STR_KWRDS const char *guf_str_const_cstr(const guf_str *str);
|
||||
GUF_STR_KWRDS char *guf_str_try_get_cstr(guf_str *str, guf_err *err); // Error if str is readonly.
|
||||
GUF_STR_KWRDS char *guf_str_cstr(guf_str *str); // Panics if str is readonly.
|
||||
|
||||
GUF_STR_KWRDS ptrdiff_t guf_str_len(const guf_str *str); // The length (in chars) without the final zero-terminator.
|
||||
GUF_STR_KWRDS ptrdiff_t guf_str_capacity(const guf_str *str); // The capacity (in chars) without the final zero-terminator.
|
||||
// Return the length/capacity (in chars) *without* the final null-terminator.
|
||||
GUF_STR_KWRDS ptrdiff_t guf_str_len(const guf_str *str);
|
||||
GUF_STR_KWRDS ptrdiff_t guf_str_capacity(const guf_str *str);
|
||||
|
||||
// Return true if the char data of the string lives directly within the guf_str itself (short-string optimisation) instead of in a separate dynamic allocation
|
||||
GUF_STR_KWRDS bool guf_str_is_short(const guf_str *str);
|
||||
// Return true if the string is in readonly ("view") mode, i.e. can't be modified, copied etc. which is useful for guf_dict so we don't have to use guf_str_view but can use guf_str (by passing a read-only guf_str) for the lookup functions.
|
||||
GUF_STR_KWRDS bool guf_str_is_readonly(const guf_str *str);
|
||||
// Return true if the string's data does not violate its invariants (useful for debugging, should never be false after initialising if there are not bugs in guf_str).
|
||||
GUF_STR_KWRDS bool guf_str_is_valid(const guf_str *str);
|
||||
|
||||
GUF_STR_KWRDS guf_str guf_str_new_uninitialised(void);
|
||||
@ -198,7 +208,7 @@ GUF_STR_KWRDS bool guf_str_is_uninit(const guf_str *str);
|
||||
}
|
||||
static inline void guf_str_set_shrt_size_(guf_str *str, unsigned char size_with_null)
|
||||
{
|
||||
GUF_ASSERT(size_with_null < GUF_STR_SSO_BUF_CAP && size_with_null < 0x80);
|
||||
GUF_ASSERT(size_with_null <= GUF_STR_SSO_BUF_CAP && size_with_null < 0x80); // TODO: was < SSO_CAP, should be <= SSO_CAP?
|
||||
str->data.shrt.size = (unsigned char)(size_with_null << 1);
|
||||
}
|
||||
#elif defined(GUF_PLATFORM_BIG_ENDIAN)
|
||||
@ -214,7 +224,7 @@ GUF_STR_KWRDS bool guf_str_is_uninit(const guf_str *str);
|
||||
}
|
||||
static inline void guf_str_set_shrt_size_(guf_str *str, unsigned char size_with_null)
|
||||
{
|
||||
GUF_ASSERT(size_with_null < GUF_STR_SSO_BUF_CAP && size_with_null < 0x80);
|
||||
GUF_ASSERT(size_with_null <= GUF_STR_SSO_BUF_CAP && size_with_null < 0x80); // TODO: was < SSO_CAP, should be <=
|
||||
str->data.shrt.size = size_with_null;
|
||||
}
|
||||
#else
|
||||
@ -328,20 +338,25 @@ GUF_STR_KWRDS bool guf_str_is_valid(const guf_str *str)
|
||||
return size > 0 && size <= GUF_STR_SSO_BUF_CAP && str->data.shrt.c_str[size - 1] == '\0';
|
||||
} else {
|
||||
const size_t cap_with_null = guf_str_cap_internal_(str) + 1;
|
||||
const size_t size = guf_str_size_internal_(str); // len + 1
|
||||
const bool valid_cap = cap_with_null > GUF_STR_SSO_BUF_CAP && cap_with_null <= PTRDIFF_MAX && (cap_with_null % 2 == 0);
|
||||
return valid_cap && str->data.lng.c_str && str->data.lng.size > 0 && str->data.lng.size <= cap_with_null;
|
||||
return valid_cap && size >= 1 && str->data.lng.c_str && str->data.lng.size > 0 && str->data.lng.size <= cap_with_null && str->data.lng.c_str[size - 1] == '\0';
|
||||
}
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t new_cap_min, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
GUF_ASSERT(!guf_str_is_readonly(str));
|
||||
|
||||
if (guf_str_is_readonly(str)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in guf_str_try_reserve: guf_str is readonly"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t old_cap_with_null = guf_str_cap_internal_(str) + 1;
|
||||
const size_t len_with_null = guf_str_len_internal_(str) + 1;
|
||||
|
||||
if (new_cap_min <= (ptrdiff_t)old_cap_with_null) { // No need to grow.
|
||||
if (new_cap_min < (ptrdiff_t)old_cap_with_null) { // No need to grow. TODO: was <=, should be < ?
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
@ -382,6 +397,7 @@ GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t new_cap_min,
|
||||
}
|
||||
memcpy(c_str_new, str->data.shrt.c_str, len_with_null);
|
||||
str->data.lng.c_str = c_str_new;
|
||||
str->data.lng.size = len_with_null;
|
||||
guf_str_set_lng_cap_(str, new_cap_min_with_null);
|
||||
} else { // b) Was long string -> need re-allocation
|
||||
char *c_str_new = str->allocator->realloc(str->data.lng.c_str, old_cap_with_null, new_cap_min_with_null, str->allocator->ctx);
|
||||
@ -398,9 +414,67 @@ GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t new_cap_min,
|
||||
return str;
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_reserve(guf_str *str, ptrdiff_t new_cap_min)
|
||||
{
|
||||
return guf_str_try_reserve(str, new_cap_min, NULL);
|
||||
}
|
||||
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_shrink_to_fit(guf_str *str, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
if (guf_str_is_readonly(str)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in guf_str_try_shrink_to_fit: guf_str is readonly"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t old_cap_with_null = guf_str_cap_internal_(str) + 1;
|
||||
const size_t len_with_null = guf_str_len_internal_(str) + 1;
|
||||
GUF_ASSERT(len_with_null <= old_cap_with_null);
|
||||
|
||||
if (old_cap_with_null == len_with_null || guf_str_is_short_internal_(str)) {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
|
||||
char *c_str_old = guf_str_cstr(str);
|
||||
GUF_ASSERT(c_str_old);
|
||||
|
||||
if (len_with_null <= GUF_STR_SSO_BUF_CAP) { // a) Shrunk size fits into short.string.
|
||||
GUF_ASSERT(len_with_null <= UCHAR_MAX)
|
||||
guf_str_set_shrt_size_(str, (unsigned char)len_with_null);
|
||||
memcpy(str->data.shrt.c_str, c_str_old, len_with_null);
|
||||
str->allocator->free(c_str_old, old_cap_with_null, str->allocator->ctx);
|
||||
GUF_ASSERT(guf_str_is_short(str));
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
// b) Shrunk size does not fit into short-string.
|
||||
char *c_str_new = str->allocator->realloc(c_str_old, old_cap_with_null, len_with_null, str->allocator->ctx);
|
||||
if (!c_str_new) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_ALLOC_FAIL, GUF_ERR_MSG("in guf_str_try_shrink_to_fit: realloc failed"));
|
||||
return NULL;
|
||||
} else {
|
||||
str->data.lng.c_str = c_str_new;
|
||||
guf_str_set_lng_cap_(str, len_with_null);
|
||||
GUF_ASSERT(!guf_str_is_short(str));
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_shrink_to_fit(guf_str *str)
|
||||
{
|
||||
return guf_str_try_shrink_to_fit(str, NULL);
|
||||
}
|
||||
|
||||
|
||||
static char *guf_str_get_cstr_internal_(guf_str *str)
|
||||
{
|
||||
if (guf_str_is_short(str)) {
|
||||
if (guf_str_is_short_internal_(str)) {
|
||||
return str->data.shrt.c_str;
|
||||
} else {
|
||||
return str->data.lng.c_str;
|
||||
@ -470,14 +544,15 @@ GUF_STR_KWRDS bool guf_str_is_uninit(const guf_str *str)
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_init_empty(guf_str *str, guf_allocator *allocator)
|
||||
{
|
||||
GUF_ASSERT(str && allocator);
|
||||
GUF_ASSERT_RELEASE(str && allocator);
|
||||
GUF_ASSERT_RELEASE(allocator->alloc && allocator->realloc && allocator->free);
|
||||
str->allocator = allocator;
|
||||
guf_str_set_shrt_size_(str, 1);
|
||||
str->data.shrt.c_str[0] = '\0';
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_init(guf_str *str, guf_str_view str_view, guf_allocator *alloc, guf_err *err)
|
||||
{
|
||||
if (!str) {
|
||||
@ -498,11 +573,14 @@ GUF_STR_KWRDS guf_str *guf_str_try_init(guf_str *str, guf_str_view str_view, guf
|
||||
if (str_view.len == 0) {
|
||||
GUF_ASSERT(!guf_str_is_readonly(str));
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
GUF_ASSERT(str_view.str && str_view.len > 0);
|
||||
|
||||
guf_str_try_reserve(str, str_view.len, err);
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_panic(*err, GUF_ERR_MSG("in guf_str_try_init: Initial allocation failed"));
|
||||
return NULL;
|
||||
@ -512,9 +590,10 @@ GUF_STR_KWRDS guf_str *guf_str_try_init(guf_str *str, guf_str_view str_view, guf
|
||||
GUF_ASSERT(!guf_str_is_readonly(str));
|
||||
|
||||
char *c_str_dst = guf_str_get_cstr_internal_(str);
|
||||
GUF_ASSERT_RELEASE(c_str_dst);
|
||||
GUF_ASSERT(c_str_dst);
|
||||
memcpy(c_str_dst, str_view.str, str_view.len);
|
||||
c_str_dst[str_view.len] = '\0';
|
||||
guf_str_set_len_internal_(str, str_view.len);
|
||||
|
||||
GUF_ASSERT(!guf_str_is_readonly(str));
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
@ -536,13 +615,65 @@ GUF_STR_KWRDS guf_str guf_str_try_new(guf_str_view str_view, guf_allocator *allo
|
||||
return guf_str_new_uninitialised();
|
||||
} else {
|
||||
GUF_ASSERT(!guf_str_is_uninit(&str));
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str guf_str_new(guf_str_view str_view, guf_allocator *alloc)
|
||||
{
|
||||
return guf_str_try_new(str_view, alloc, NULL);
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_init_from_cstr(guf_str *str, const char* c_str, guf_allocator *alloc, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(str);
|
||||
if (!str) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, GUF_ERR_MSG("in guf_str_try_init_from_cstr: str is NULL"));
|
||||
return NULL;
|
||||
} else if (!c_str) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, GUF_ERR_MSG("in guf_str_try_init_from_cstr: c_str is NULL"));
|
||||
return NULL;
|
||||
} else if (!alloc || !alloc->alloc || !alloc->realloc || !alloc->free) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, GUF_ERR_MSG("in guf_str_try_init_from_cstr: alloc (or allocs function pointers) is/are NULL"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t len = strlen(c_str);
|
||||
if (len >= PTRDIFF_MAX) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in guf_str_try_init_from_cstr: stlen(c_str) >= PTRDIFF_MAX"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guf_str_try_init(str, (guf_str_view){.str = c_str, .len = (ptrdiff_t)len}, alloc, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, *err, GUF_ERR_MSG("in guf_str_try_init_from_cstr: guf_str_try_init failed"));
|
||||
return NULL;
|
||||
} else {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_init_from_cstr(guf_str *str, const char* c_str, guf_allocator *alloc)
|
||||
{
|
||||
return guf_str_try_init_from_cstr(str, c_str, alloc, NULL);
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str_view guf_str_to_view(const guf_str *str)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
guf_str_view sv = {
|
||||
.str = guf_str_const_cstr(str),
|
||||
.len = guf_str_len(str)
|
||||
};
|
||||
GUF_ASSERT(guf_str_view_is_valid(sv));
|
||||
return sv;
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS char *guf_str_try_at(guf_str *str, ptrdiff_t idx, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT_RELEASE(guf_str_is_valid(str));
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
const ptrdiff_t len = guf_str_len(str);
|
||||
|
||||
@ -555,6 +686,7 @@ GUF_STR_KWRDS char *guf_str_try_at(guf_str *str, ptrdiff_t idx, guf_err *err)
|
||||
} else {
|
||||
char *c_str = guf_str_try_get_cstr(str, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, *err, GUF_ERR_MSG("in guf_str_try_at: guf_str_try_get_cstr failed (guf_str is readonly)"));
|
||||
return NULL;
|
||||
}
|
||||
GUF_ASSERT(c_str);
|
||||
@ -576,6 +708,7 @@ GUF_STR_KWRDS char *guf_str_try_back(guf_str *str, guf_err *err)
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in guf_str_try_back: len == 0"));
|
||||
return NULL;
|
||||
} else {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return guf_str_try_at(str, len - 1, err);
|
||||
}
|
||||
}
|
||||
@ -593,6 +726,7 @@ GUF_STR_KWRDS char *guf_str_try_front(guf_str *str, guf_err *err)
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in guf_str_try_front: len == 0"));
|
||||
return NULL;
|
||||
} else {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return guf_str_try_at(str, 0, err);
|
||||
}
|
||||
}
|
||||
@ -604,8 +738,8 @@ GUF_STR_KWRDS char *guf_str_front(guf_str *str)
|
||||
|
||||
GUF_STR_KWRDS char guf_str_try_at_cpy(const guf_str *str, ptrdiff_t idx, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
const ptrdiff_t len = guf_str_len(str);
|
||||
|
||||
if (idx < 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in guf_str_try_at_cpy: idx < 0"));
|
||||
return '\0';
|
||||
@ -633,6 +767,7 @@ GUF_STR_KWRDS char guf_str_try_back_cpy(const guf_str *str, guf_err *err)
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in guf_str_try_back_cpy: len == 0"));
|
||||
return '\0';
|
||||
} else {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return guf_str_try_at_cpy(str, len - 1, err);
|
||||
}
|
||||
}
|
||||
@ -650,6 +785,7 @@ GUF_STR_KWRDS char guf_str_try_front_cpy(const guf_str *str, guf_err *err)
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in guf_str_try_front_cpy: len == 0"));
|
||||
return '\0';
|
||||
} else {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return guf_str_try_at_cpy(str, 0, err);
|
||||
}
|
||||
}
|
||||
@ -763,17 +899,55 @@ GUF_STR_KWRDS int guf_str_cmp(const guf_str *a, const guf_str *b)
|
||||
return memcmp(a_cstr, b_cstr, shorter_len);
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_set(guf_str *str, guf_str_view sv, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
if (guf_str_is_readonly(str)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in guf_str_try_set: guf_str is readonly"));
|
||||
return NULL;
|
||||
} else if (!guf_str_view_is_valid(sv)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in guf_str_try_set: str_view is invalid"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guf_str_try_reserve(str, sv.len, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, *err, GUF_ERR_MSG("in guf_str_try_set: guf_str_try_reserve failed"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *c_str_dst = guf_str_cstr(str);
|
||||
GUF_ASSERT(c_str_dst);
|
||||
if (sv.len > 0) {
|
||||
GUF_ASSERT(sv.str);
|
||||
memcpy(c_str_dst, sv.str, sv.len);
|
||||
}
|
||||
c_str_dst[sv.len] = '\0';
|
||||
guf_str_set_len_internal_(str, sv.len);
|
||||
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_set(guf_str *str, guf_str_view sv)
|
||||
{
|
||||
return guf_str_try_set(str, sv, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_append_char(guf_str *str, char c, ptrdiff_t times, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
if (guf_str_is_readonly(str)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, "in guf_str_try_append_char: str is readonly");
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, GUF_ERR_MSG("in guf_str_try_append_char: str is readonly"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (times < 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, "in guf_str_try_append_char: repeats < 0");
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in guf_str_try_append_char: repeats < 0"));
|
||||
return NULL;
|
||||
} else if (times == 0) {
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
@ -787,12 +961,12 @@ GUF_STR_KWRDS guf_str *guf_str_try_append_char(guf_str *str, char c, ptrdiff_t t
|
||||
|
||||
const size_t new_len = old_len + (size_t)times;
|
||||
if (new_len <= old_len || new_len >= (size_t)PTRDIFF_MAX) { // Handle overflow.
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_char: new length would overflow ptrdiff_t");
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in guf_str_try_append_char: new length would overflow ptrdiff_t"));
|
||||
return NULL;
|
||||
} else if (new_len > old_cap) { // Need to grow capacity.
|
||||
guf_str_try_reserve(str, new_len, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, *err, "in guf_str_try_append_char: failed to reserve capacity");
|
||||
guf_err_set_or_panic(err, *err, GUF_ERR_MSG("in guf_str_try_append_char: failed to reserve capacity"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -833,10 +1007,10 @@ GUF_STR_KWRDS guf_str *guf_str_try_append(guf_str *str, guf_str_view sv, guf_err
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
if (!guf_str_view_is_valid(sv)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, "in guf_str_try_append_view: str_view is invalid");
|
||||
guf_err_set_or_panic(err, GUF_ERR_INVALID_ARG, GUF_ERR_MSG("in guf_str_try_append_view: str_view is invalid"));
|
||||
return NULL;
|
||||
} else if (guf_str_is_readonly(str)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, "in in guf_str_try_append_view: str is readonly");
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, GUF_ERR_MSG("in in guf_str_try_append_view: str is readonly"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -850,12 +1024,12 @@ GUF_STR_KWRDS guf_str *guf_str_try_append(guf_str *str, guf_str_view sv, guf_err
|
||||
const size_t old_len = guf_str_len_internal_(str);
|
||||
const size_t new_len = old_len + (size_t)sv.len;
|
||||
if (new_len <= old_len || new_len >= (size_t)PTRDIFF_MAX) { // Handle overflow.
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_view: new length would overflow ptrdiff_t");
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in guf_str_try_append_view: new length would overflow ptrdiff_t"));
|
||||
return NULL;
|
||||
} else if (new_len > old_cap) { // Growth necessary.
|
||||
guf_str_try_reserve(str, new_len, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, *err, "in guf_str_try_append_view: failed to reserve capacity");
|
||||
guf_err_set_or_panic(err, *err, GUF_ERR_MSG("in guf_str_try_append_view: failed to reserve capacity"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -882,55 +1056,6 @@ GUF_STR_KWRDS guf_str *guf_str_append(guf_str *str, guf_str_view sv)
|
||||
return guf_str_try_append(str, sv, NULL);
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_append_cstr(guf_str *str, const char *c_str, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
if (!c_str) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, "in guf_str_try_append_cstr: c_str is NULL");
|
||||
return NULL;
|
||||
} else if (guf_str_is_readonly(str)) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_NULL_PTR, "in guf_str_try_append_cstr: str is readonly");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *dst_cstr = guf_str_get_cstr_internal_(str);
|
||||
size_t i = 0;
|
||||
do {
|
||||
size_t cap = guf_str_cap_internal_(str);
|
||||
size_t len = guf_str_len_internal_(str);
|
||||
GUF_ASSERT(len <= cap);
|
||||
|
||||
if (len == cap) { // Grow if necessary.
|
||||
if (cap == PTRDIFF_MAX) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_cstr: cannot grow (capacity is PTRDIFF_MAX)");
|
||||
return NULL;
|
||||
}
|
||||
guf_str_try_reserve(str, cap + 1, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_INT_OVERFLOW, "in guf_str_try_append_cstr: failed to reserve");
|
||||
return NULL;
|
||||
}
|
||||
cap = guf_str_cap_internal_(str);
|
||||
len = guf_str_len_internal_(str);
|
||||
}
|
||||
|
||||
dst_cstr[len] = c_str[i];
|
||||
guf_str_set_len_internal_(str, len + 1);
|
||||
} while (c_str[i++] != '\0');
|
||||
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
GUF_ASSERT(dst_cstr[guf_str_len_internal_(str)] == '\0');
|
||||
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return str;
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_append_cstr(guf_str *str, const char *c_str)
|
||||
{
|
||||
return guf_str_try_append_cstr(str, c_str, NULL);
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS guf_str *guf_str_try_substr(guf_str *str, ptrdiff_t pos, ptrdiff_t count, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
@ -975,6 +1100,33 @@ GUF_STR_KWRDS guf_str *guf_str_substr(guf_str *str, ptrdiff_t pos, ptrdiff_t cou
|
||||
return guf_str_try_substr(str, pos, count, NULL);
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS char guf_str_try_pop_back(guf_str *str, guf_err *err)
|
||||
{
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
|
||||
const ptrdiff_t len = guf_str_len(str);
|
||||
if (len <= 0) {
|
||||
guf_err_set_or_panic(err, GUF_ERR_IDX_RANGE, GUF_ERR_MSG("in guf_str_try_pop_back: len <= 0"));
|
||||
return '\0';
|
||||
}
|
||||
GUF_ASSERT(len - 1 >= 0);
|
||||
const char last = guf_str_at_cpy(str, len - 1);
|
||||
guf_str_try_substr(str, 0, len - 1, err);
|
||||
if (err && *err != GUF_ERR_NONE) {
|
||||
guf_err_set_or_panic(err, *err, GUF_ERR_MSG("in guf_str_try_pop_back: guf_str_try_substr failed"));
|
||||
return '\0';
|
||||
} else {
|
||||
GUF_ASSERT(guf_str_is_valid(str));
|
||||
GUF_ASSERT(guf_str_len(str) == len - 1);
|
||||
guf_err_set_if_not_null(err, GUF_ERR_NONE);
|
||||
return last;
|
||||
}
|
||||
}
|
||||
|
||||
GUF_STR_KWRDS char guf_str_pop_back(guf_str *str)
|
||||
{
|
||||
return guf_str_try_pop_back(str, NULL);
|
||||
}
|
||||
|
||||
|
||||
// guf_str_view:
|
||||
|
||||
@ -11,6 +11,7 @@ extern "C" {
|
||||
#include "test_dbuf.hpp"
|
||||
#include "test_dict.hpp"
|
||||
#include "test_utf8.hpp"
|
||||
#include "test_str.hpp"
|
||||
|
||||
std::unordered_set<std::unique_ptr<Test>> g_tests {};
|
||||
|
||||
@ -31,6 +32,10 @@ void init_tests()
|
||||
test = std::make_unique<UTF8Test>("UTF8Test");
|
||||
GUF_ASSERT_RELEASE(test.get());
|
||||
g_tests.insert(std::move(test));
|
||||
|
||||
test = std::make_unique<StrTest>("StrTest");
|
||||
GUF_ASSERT_RELEASE(test.get())
|
||||
g_tests.insert(std::move(test));
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
212
src/test/test_str.hpp
Normal file
212
src/test/test_str.hpp
Normal file
@ -0,0 +1,212 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "guf_alloc_libc.h"
|
||||
#include "guf_str.h"
|
||||
}
|
||||
|
||||
struct StrTest : public Test
|
||||
{
|
||||
public:
|
||||
StrTest(const std::string& name) : Test(name) {};
|
||||
|
||||
private:
|
||||
void test_init_free(std::string str)
|
||||
{
|
||||
guf_str s0;
|
||||
guf_str_init(&s0, GUF_CSTR_TO_VIEW_CPP(str.c_str()), &guf_allocator_libc);
|
||||
guf_str s1 = guf_str_new(GUF_CSTR_TO_VIEW_CPP(str.c_str()), &guf_allocator_libc);
|
||||
guf_str s2;
|
||||
guf_str_init_from_cstr(&s2, str.c_str(), &guf_allocator_libc);
|
||||
|
||||
TEST_CHECK(guf_str_equal(&s0, &s1));
|
||||
TEST_CHECK(guf_str_equal(&s0, &s2));
|
||||
TEST_CHECK(guf_str_equal(&s1, &s2));
|
||||
|
||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s0));
|
||||
TEST_CHECK(str == guf_str_const_cstr(&s0));
|
||||
TEST_CHECK(str == guf_str_cstr(&s0));
|
||||
|
||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s1));
|
||||
TEST_CHECK(str == guf_str_const_cstr(&s1));
|
||||
TEST_CHECK(str == guf_str_cstr(&s1));
|
||||
|
||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s2));
|
||||
TEST_CHECK(str == guf_str_const_cstr(&s2));
|
||||
TEST_CHECK(str == guf_str_cstr(&s2));
|
||||
|
||||
guf_str_free(&s0, NULL);
|
||||
guf_str_free(&s1, NULL);
|
||||
guf_str_free(&s2, NULL);
|
||||
TEST_CHECK(guf_str_is_uninit(&s0));
|
||||
TEST_CHECK(guf_str_is_uninit(&s1));
|
||||
TEST_CHECK(guf_str_is_uninit(&s2));
|
||||
}
|
||||
|
||||
void test_init_empty()
|
||||
{
|
||||
std::string str = "";
|
||||
guf_str s = GUF_STR_UNINITIALISED_CPP;
|
||||
guf_str_init_empty(&s, &guf_allocator_libc);
|
||||
TEST_CHECK(guf_str_len(&s) == 0);
|
||||
TEST_CHECK(str == guf_str_const_cstr(&s));
|
||||
|
||||
guf_str_append_char(&s, 'a', 1024);
|
||||
str.append(1024, 'a');
|
||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
||||
|
||||
guf_str_append_char(&s, 'b', 24);
|
||||
str.append(24, 'b');
|
||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
||||
|
||||
guf_str_append_char(&s, 'c', 255);
|
||||
str.append(255, 'c');
|
||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
||||
|
||||
*guf_str_at(&s, 0) = '<';
|
||||
str.at(0) = '<';
|
||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
||||
|
||||
*guf_str_at(&s, guf_str_len(&s) - 1) = '>';
|
||||
str.at(str.size() - 1) = '>';
|
||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
||||
|
||||
guf_err err = GUF_ERR_NONE;
|
||||
TEST_CHECK(NULL == guf_str_try_at(&s, guf_str_len(&s), &err));
|
||||
TEST_CHECK(err != GUF_ERR_NONE && err == GUF_ERR_IDX_RANGE);
|
||||
err = GUF_ERR_NONE;
|
||||
TEST_CHECK(NULL == guf_str_try_at(&s, -1, &err));
|
||||
TEST_CHECK(err != GUF_ERR_NONE && err == GUF_ERR_IDX_RANGE);
|
||||
|
||||
guf_str_free(&s, NULL);
|
||||
TEST_CHECK(guf_str_is_uninit(&s));
|
||||
}
|
||||
|
||||
void test_append_char(std::string str, bool include_null = false)
|
||||
{
|
||||
guf_str s0 = guf_str_new(guf_str_view{.str = str.c_str(), .len = (ptrdiff_t)str.size()}, &guf_allocator_libc);
|
||||
|
||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s0));
|
||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
|
||||
for (int i = include_null ? 0 : 1; i < 128; ++i) {
|
||||
char ch = (char)i;
|
||||
guf_str_append_one_char(&s0, ch);
|
||||
str.append(1, ch);
|
||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
}
|
||||
|
||||
for (int i = include_null ? 0 : 1; i < 128; ++i) {
|
||||
char ch = (char)i;
|
||||
guf_str_append_char(&s0, ch, i);
|
||||
str.append(i, ch);
|
||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
guf_str_append_char(&s0, ch, i * 16);
|
||||
str.append(i * 16, ch);
|
||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str.size());
|
||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
}
|
||||
|
||||
guf_str_free(&s0, NULL);
|
||||
TEST_CHECK(guf_str_is_uninit(&s0));
|
||||
}
|
||||
|
||||
void append_str(const std::string& a, const std::string& b)
|
||||
{
|
||||
std::string str0 = a;
|
||||
guf_str s0 = guf_str_new(guf_str_view{.str = str0.c_str(), .len = (ptrdiff_t)str0.size()}, &guf_allocator_libc);
|
||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str0.size());
|
||||
TEST_CHECK((str0 == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
TEST_CHECK((str0 == std::string_view{guf_str_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
|
||||
for (int i = 0; i <= 64; ++i) {
|
||||
str0.append(b);
|
||||
guf_str_append(&s0, guf_str_view{.str = b.c_str(), .len = (ptrdiff_t)b.size()});
|
||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str0.size());
|
||||
TEST_CHECK((str0 == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
TEST_CHECK((str0 == std::string_view{guf_str_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
||||
}
|
||||
|
||||
guf_str_free(&s0, NULL);
|
||||
TEST_CHECK(guf_str_is_uninit(&s0));
|
||||
}
|
||||
|
||||
public:
|
||||
bool run()
|
||||
{
|
||||
if (done) {
|
||||
return passed;
|
||||
}
|
||||
|
||||
const std::vector<std::string> words = {
|
||||
"",
|
||||
"\0",
|
||||
"Hello",
|
||||
"Othell\0o",
|
||||
"f\0\0",
|
||||
"\0",
|
||||
"0",
|
||||
"a",
|
||||
"ab",
|
||||
"🌈 waow a rainboge!",
|
||||
"orange cat(1) :3",
|
||||
"xes yag",
|
||||
"Hello, world! This is a pretty darn long string I'd say...",
|
||||
"I want to eat crayons. I crave crayons because they are tasty, and everybody telling me crayons are not edible must be either lying or dumb. I like trains. 42 is a number. 3.14159265... is not a rational number, and it is called pi. I ate some pie (it was a crayon pie).",
|
||||
std::string(32, 'a'),
|
||||
std::string(64, 'b'),
|
||||
std::string(1024, 'a'),
|
||||
std::string(2048, 'a'),
|
||||
std::string(4096, 'a'),
|
||||
std::string(5001, 'a'),
|
||||
std::string(7121, 'a'),
|
||||
std::string(2000, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP - 1, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP + 1, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP - 2, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP + 2, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP - 3, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP + 3, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP * 2, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP * 3, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP * 4, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP * 5, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP * 6, 'a'),
|
||||
std::string(GUF_STR_SSO_BUF_CAP * 7, 'a'),
|
||||
};
|
||||
|
||||
test_init_empty();
|
||||
|
||||
for (const auto& word : words) {
|
||||
test_init_free(word);
|
||||
test_append_char(word);
|
||||
test_append_char(word, true);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < words.size(); ++i) {
|
||||
const auto& w1 = words.at(i);
|
||||
append_str(w1, w1);
|
||||
append_str(w1, w1);
|
||||
for (size_t j = i + 1; j < words.size(); ++j) {
|
||||
const auto& w2 = words.at(j);
|
||||
append_str(w1, w2);
|
||||
append_str(w2, w1);
|
||||
}
|
||||
}
|
||||
|
||||
done = true;
|
||||
passed = (num_failed_checks == 0);
|
||||
return passed;
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user