str.h (4587B)
1 /* Copyright (C) 2013-2023, 2025 Vincent Forest (vaplv@free.fr) 2 * 3 * The RSys library is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published 5 * by the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * The RSys library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #ifndef STR_H 17 #define STR_H 18 19 #include "hash.h" 20 #include "mem_allocator.h" 21 #include "rsys.h" 22 23 #include <stdarg.h> 24 #include <string.h> 25 26 struct str { 27 /* Internal data. Should not be publicly accessed */ 28 struct mem_allocator* allocator; 29 size_t allocated; /* <=> string capacity */ 30 char* cstr; 31 char buffer[16]; /* static buffer. Avoid allocation on small string */ 32 }; 33 34 static INLINE void 35 str_init(struct mem_allocator* allocator, struct str* str) 36 { 37 ASSERT(str); 38 str->allocator = allocator ? allocator : &mem_default_allocator; 39 str->allocated = sizeof(str->buffer); 40 str->cstr = str->buffer; 41 str->buffer[0] = '\0'; 42 } 43 44 static INLINE void 45 str_release(struct str* str) 46 { 47 ASSERT(str); 48 if(str->cstr != str->buffer) 49 MEM_RM(str->allocator, str->cstr); 50 str->cstr = NULL; 51 } 52 53 static INLINE size_t 54 str_len(const struct str* str) 55 { 56 ASSERT(str); 57 return strlen(str->cstr); 58 } 59 60 static INLINE char 61 str_is_empty(const struct str* str) 62 { 63 ASSERT(str); 64 return str_len(str) == 0; 65 } 66 67 static INLINE void 68 str_clear(struct str* str) 69 { 70 ASSERT(str); 71 str->cstr[0] = '\0'; 72 } 73 74 static INLINE char* 75 str_get(struct str* str) 76 { 77 ASSERT(str); 78 return str->cstr; 79 } 80 81 static INLINE const char* 82 str_cget(const struct str* str) 83 { 84 ASSERT(str); 85 return str->cstr; 86 } 87 88 static INLINE int 89 str_cmp(const struct str* str0, const struct str* str1) 90 { 91 ASSERT(str0 && str1); 92 return strcmp(str_cget(str0), str_cget(str1)); 93 } 94 95 static INLINE char 96 str_eq(const struct str* str0, const struct str* str1) 97 { 98 return str_cmp(str0, str1) == 0; 99 } 100 101 BEGIN_DECLS 102 103 RSYS_API res_T str_set(struct str* str, const char* cstr); 104 RSYS_API res_T str_insert(struct str* str, const size_t i, const char* cstr); 105 RSYS_API res_T str_insert_char(struct str* str, const size_t i, const char ch); 106 RSYS_API res_T str_append(struct str* str, const char* cstr); 107 RSYS_API res_T str_append_char(struct str* str, const char ch); 108 RSYS_API res_T str_reserve(struct str* str, const size_t capacity); 109 110 RSYS_API res_T 111 str_printf 112 (struct str* str, 113 const char* fmt, 114 ...) 115 #ifdef COMPILER_GCC 116 __attribute__((format(printf, 2, 3))) 117 #endif 118 ; 119 120 RSYS_API res_T 121 str_append_printf 122 (struct str* str, 123 const char* fmt, 124 ...) 125 #ifdef COMPILER_GCC 126 __attribute__((format(printf, 2, 3))) 127 #endif 128 ; 129 130 RSYS_API res_T 131 str_vprintf 132 (struct str* str, 133 const char* fmt, 134 va_list vargs_list); 135 136 RSYS_API res_T 137 str_append_vprintf 138 (struct str* str, 139 const char* fmt, 140 va_list vargs_list); 141 142 END_DECLS 143 144 static INLINE res_T 145 str_copy(struct str* dst, const struct str* src) 146 { 147 ASSERT(dst && src); 148 if(dst == src) 149 return RES_OK; 150 return str_set(dst, str_cget(src)); 151 } 152 153 static INLINE res_T 154 str_copy_and_clear(struct str* dst, struct str* src) 155 { 156 res_T res = RES_OK; 157 ASSERT(dst && src); 158 if(dst == src) { 159 str_clear(dst); 160 return RES_OK; 161 } 162 163 if(src->cstr != src->buffer && src->allocator == dst->allocator) { 164 /* Give the ownership of src->cstr to dst */ 165 if(dst->cstr != dst->buffer ) 166 MEM_RM(dst->allocator, dst->cstr); 167 dst->cstr = src->cstr; 168 dst->allocated = src->allocated; 169 /* Reset the src to its initial state */ 170 str_init(src->allocator, src); 171 } else { 172 res = str_copy(dst, src); 173 if(res == RES_OK) 174 str_clear(src); 175 } 176 return res; 177 } 178 179 static INLINE res_T 180 str_copy_and_release(struct str* dst, struct str* src) 181 { 182 res_T res = RES_OK; 183 ASSERT( dst && src ); 184 if(dst == src) { 185 str_release(dst); 186 } else { 187 res = str_copy_and_clear(dst, src); 188 if(res == RES_OK) 189 str_release(src); 190 } 191 return res; 192 } 193 194 static INLINE size_t 195 str_hash(const struct str* str) 196 { 197 const char* c_str; 198 ASSERT(str); 199 c_str = str_cget(str); 200 #ifdef ARCH_32BITS 201 return (size_t)hash_fnv32(c_str, str_len(str)); 202 #elif defined ARCH_64BITS 203 return (size_t)hash_fnv64(c_str, str_len(str)); 204 #else 205 #error "Unexpected architecture" 206 #endif 207 } 208 209 #endif /* STR_H */