#ifndef _AL_STR_H #define _AL_STR_H #include "lib.h" typedef struct { u32 len; u32 alloc; char *data; } str; #define al_str_zero() (str){ 0, 0, NULL } #define al_str_at(s, i) (s)->data[i] #define al_str_atr(s, i) (s)->data[(s)->len + i] #define al_string_if_literal(s) ((char *)(s "")) // use al_str_cr for runtime. #define al_str_c(s) (&((str){ (u32)((sizeof(s) / sizeof(char)) - 1), 0, al_string_if_literal(s) })) #define al_str_cr(s) (&((str){ (u32)al_strlen(s), 0, ((char *)(s)) })) // runtime #define al_str_w(s, i, n) (&((str){ ((u32)(n)), 0, &(s)[i] })) #define al_str_substr(s, start, end) al_str_w((s)->data, start, ((end) - (start))) #define AL_STR_FMT "%.*s" #define AL_STR_PRINTF(s) (s)->len, (s)->data #define AL_STR_PRINTF_MAXLEN(s, l) AL_MIN((s)->len, (l)), (s)->data AL_UNUSED_FUNCTION_PUSH static inline bool al_str_is_empty(str *s) { return s->len == 0; } static inline void al_str_free(str *s) { if (s->alloc > 0) al_free(s->data); } static inline u32 al_str_reserve(str *s, u32 size) { if (size < al_grow_limit) { size = (u32)al_next_power_of_two(size + 1); } else { size = (u32)((size + al_grow_limit) & ~al_grow_limit); } if (size <= s->alloc) return s->alloc; s->data = (char *)((!s->data) ? al_malloc(size) : al_realloc(s->data, size)); return size; } static inline void al_str_sized(str *s, u32 size) { *s = al_str_zero(); s->alloc = al_str_reserve(s, size); } static inline void al_str_clone(str *dest, str *src) { al_str_sized(dest, src->len); al_memcpy(dest->data, src->data, src->len); dest->len = src->len; } static inline void al_str_from(str *s, const char *c_str) { if (!c_str) { *s = al_str_zero(); return; } size_t len = al_strlen(c_str); al_str_sized(s, (u32)len); al_memcpy(s->data, c_str, len); s->len = (u32)len; } static inline void al_str_to_lower(str *s) { for (u32 i = 0; i < s->len; i++) { al_str_at(s, i) = tolower(al_str_at(s, i)); } } // Returned c_str must be free'd by the user. static inline char *al_str_to_c_str(str *s) { char *c = (char *)al_malloc(s->len + 1); al_memcpy(c, s->data, s->len); c[s->len] = '\0'; return c; } static inline void al_str_cat(str *s, str *c) { s->alloc = al_str_reserve(s, s->len + c->len); al_memcpy(s->data + s->len, c->data, c->len); s->len += c->len; } static inline void al_str_insert(str *s, u32 i, str *c) { s->alloc = al_str_reserve(s, s->len + c->len); char *data = s->data + i; al_memmove(data + c->len, data, s->len - i); al_memcpy(data, c->data, c->len); s->len += c->len; } static inline void al_str_prepend(str *s, str *c) { al_str_insert(s, 0, c); } static inline s32 al_str_cmp(str *s, str *c, u32 start, u32 len) { if (start + len > s->len || len > c->len) { return -1; } return al_memcmp(&al_str_at(s, start), c->data, len); } static inline bool al_str_eq(str *s, str *c) { return al_str_cmp(s, c, 0, AL_MAX(s->len, c->len)) == 0; } static inline s32 al_str_find(str *s, char c) { char *loc = (char *)al_memchr(s->data, c, s->len); if (!loc) return -1; return (s32)(loc - s->data); } static inline s32 al_str_rfind(str *s, char c) { char *loc = (char *)al_memrchr(s->data, c, s->len); if (!loc) return -1; return (s32)(loc - s->data); } // extremely slow. static inline s32 al_str_find_str(str *s, str *c) { if (c->len > s->len) return -1; for (u32 i = 0; i < s->len - c->len; i++) { if (al_str_at(s, i) != al_str_at(c, 0)) continue; if (al_str_cmp(s, c, i, c->len) == 0) { return i; } } return -1; } static inline u32 al_str_hash(str *s) { u32 hash = 5381; for (u32 i = 0; i < s->len; i++) { hash = ((hash << 5) + hash) + al_str_at(s, i); /* hash * 33 + c */ } return hash; } AL_UNUSED_FUNCTION_POP s64 al_str_to_long(str *s, s32 base); bool al_str_get_line(str *buffer, char sep, str *line); #endif // _AL_STR_H