added null-terminate option for strings
Minclude/cutils/dyn_string.h
| @@ -12,10 +12,11 @@ typedef struct String | |||
|---|---|---|---|
| 12 | 12 | char* chars; | |
| 13 | 13 | size_t capacity; | |
| 14 | 14 | size_t length; | |
| 15 | + | bool null_terminated; | |
| 15 | 16 | } String; | |
| 16 | 17 | ||
| 17 | - | #define new_string() string_with_capacity(STRING_DEFAULT_SIZE) | |
| 18 | - | String* string_with_capacity(size_t capacity); | |
| 18 | + | #define new_string(null_terminated) string_with_capacity(STRING_DEFAULT_SIZE, null_terminated) | |
| 19 | + | String* string_with_capacity(size_t capacity, bool null_terminated); | |
| 19 | 20 | void delete_string(String* string); | |
| 20 | 21 | ||
| 21 | 22 | HEDLEY_INLINE | |
| @@ -35,7 +36,7 @@ static void string_remove(String* string, size_t index) | |||
|---|---|---|---|
| 35 | 36 | { | |
| 36 | 37 | if(index < string->length) | |
| 37 | 38 | { | |
| 38 | - | memmove(string->chars+index, string->chars+index+1, (string->length-index-1)*sizeof(*string->chars)); | |
| 39 | + | memmove(string->chars+index, string->chars+index+1, (string->length-index-1+(string->null_terminated?1:0))*sizeof(*string->chars)); | |
| 39 | 40 | string->length--; | |
| 40 | 41 | } | |
| 41 | 42 | } | |
| @@ -59,9 +60,9 @@ size_t string_count(const String* string, char character); | |||
|---|---|---|---|
| 59 | 60 | ||
| 60 | 61 | bool string_concat(String* string, const String* other); | |
| 61 | 62 | ||
| 62 | - | String* from_cstring(const char* cstring); | |
| 63 | - | String* from_cstring_reuse(char* cstring, size_t capacity); | |
| 64 | - | String* from_cstring_del(char* cstring); | |
| 63 | + | String* from_cstring(const char* cstring, bool null_terminated); | |
| 64 | + | String* from_cstring_reuse(char* cstring, size_t capacity, bool null_terminated); | |
| 65 | + | String* from_cstring_del(char* cstring, bool null_terminated); | |
| 65 | 66 | char* to_cstring(const String* string); | |
| 66 | 67 | char* to_cstring_del(String* string); | |
| 67 | 68 | void string_move(String* dest, String* src); | |
Msrc/dyn_string.c
| @@ -1,25 +1,28 @@ | |||
|---|---|---|---|
| 1 | 1 | #include <cutils/dyn_string.h> | |
| 2 | 2 | ||
| 3 | - | String* string_with_capacity(size_t capacity) | |
| 3 | + | String* string_with_capacity(size_t capacity, bool null_terminated) | |
| 4 | 4 | { | |
| 5 | 5 | String* string = malloc(sizeof(*string)); | |
| 6 | 6 | if(!string) | |
| 7 | 7 | return NULL; | |
| 8 | - | string->chars = calloc(capacity,sizeof(*string->chars)); | |
| 8 | + | string->chars = malloc(capacity+(null_terminated?1:0)); | |
| 9 | 9 | if(!string->chars) | |
| 10 | 10 | { | |
| 11 | 11 | free(string); | |
| 12 | 12 | return NULL; | |
| 13 | 13 | } | |
| 14 | + | if(null_terminated) | |
| 15 | + | string->chars[0] = '\0'; | |
| 14 | 16 | string->length = 0; | |
| 15 | 17 | string->capacity = capacity; | |
| 18 | + | string->null_terminated = null_terminated; | |
| 16 | 19 | ||
| 17 | 20 | return string; | |
| 18 | 21 | } | |
| 19 | 22 | ||
| 20 | 23 | void string_remove_range(String* string, size_t index, size_t length) | |
| 21 | 24 | { | |
| 22 | - | memmove(string->chars+index, string->chars+index+length, (string->length-(index+length))); | |
| 25 | + | memmove(string->chars+index, string->chars+index+length, (string->length-(index+length)+(string->null_terminated?1:0))); | |
| 23 | 26 | string->length -= length; | |
| 24 | 27 | } | |
| 25 | 28 | ||
| @@ -44,7 +47,7 @@ size_t string_strip(String* string, char character) | |||
|---|---|---|---|
| 44 | 47 | } | |
| 45 | 48 | } | |
| 46 | 49 | ||
| 47 | - | memmove(string->chars+last-offset, string->chars+last+1, string->length-last-1); | |
| 50 | + | memmove(string->chars+last-offset, string->chars+last+1, string->length-last-1+(string->null_terminated?1:0)); | |
| 48 | 51 | ||
| 49 | 52 | string->length -= offset+(first ? 0 : 1); | |
| 50 | 53 | return offset; | |
| @@ -52,10 +55,10 @@ size_t string_strip(String* string, char character) | |||
|---|---|---|---|
| 52 | 55 | ||
| 53 | 56 | bool string_insert(String* string, size_t index, char character) | |
| 54 | 57 | { | |
| 55 | - | if(index > string->length || string->length == SIZE_MAX || !string_adjust_size(string, string->length)) | |
| 58 | + | if(index > string->length || string->length == SIZE_MAX || !string_adjust_size(string, string->length+1)) | |
| 56 | 59 | return false; | |
| 57 | 60 | ||
| 58 | - | memmove(string->chars+index+1, string->chars+index, (string->length-index)*sizeof(*string->chars)); | |
| 61 | + | memmove(string->chars+index+1, string->chars+index, (string->length-index+(string->null_terminated?1:0))*sizeof(*string->chars)); | |
| 59 | 62 | string->chars[index] = character; | |
| 60 | 63 | string->length++; | |
| 61 | 64 | return true; | |
| @@ -64,13 +67,8 @@ bool string_insert(String* string, size_t index, char character) | |||
|---|---|---|---|
| 64 | 67 | char string_pop_at(String* string, size_t index) | |
| 65 | 68 | { | |
| 66 | 69 | char tmp = string_at(string, index); | |
| 67 | - | if(!tmp) | |
| 68 | - | { | |
| 69 | - | return '\0'; | |
| 70 | - | } else { | |
| 71 | - | string_remove(string, index); | |
| 72 | - | return tmp; | |
| 73 | - | } | |
| 70 | + | string_remove(string, index); | |
| 71 | + | return tmp; | |
| 74 | 72 | } | |
| 75 | 73 | ||
| 76 | 74 | bool string_concat(String* string, const String* other) | |
| @@ -79,6 +77,7 @@ bool string_concat(String* string, const String* other) | |||
|---|---|---|---|
| 79 | 77 | return false; | |
| 80 | 78 | memcpy(string->chars+string->length,other->chars,other->length); | |
| 81 | 79 | string->length += other->length; | |
| 80 | + | string->chars[string->length] = '\0'; | |
| 82 | 81 | return true; | |
| 83 | 82 | } | |
| 84 | 83 | ||
| @@ -110,7 +109,10 @@ size_t string_count(const String* string, char character) | |||
|---|---|---|---|
| 110 | 109 | ||
| 111 | 110 | bool string_adjust_size(String* string, size_t size) | |
| 112 | 111 | { | |
| 113 | - | while(string->capacity < size) | |
| 112 | + | if(size == SIZE_MAX && string->null_terminated) | |
| 113 | + | return false; | |
| 114 | + | ||
| 115 | + | while(string->capacity < size+(string->null_terminated?1:0)) | |
| 114 | 116 | { | |
| 115 | 117 | char* tmp = string->chars; | |
| 116 | 118 | string->chars = cutil_reallocarray_inc(string->chars, sizeof(*string->chars), string->capacity, string->capacity); | |
| @@ -131,20 +133,22 @@ void delete_string(String* string) | |||
|---|---|---|---|
| 131 | 133 | free(string); | |
| 132 | 134 | } | |
| 133 | 135 | ||
| 134 | - | String* from_cstring(const char* cstring) | |
| 136 | + | String* from_cstring(const char* cstring, bool null_terminated) | |
| 135 | 137 | { | |
| 136 | - | String* string = string_with_capacity(strlen(cstring)); | |
| 138 | + | String* string = string_with_capacity(strlen(cstring), null_terminated); | |
| 137 | 139 | if(!string) | |
| 138 | 140 | { | |
| 139 | 141 | return NULL; | |
| 140 | 142 | } else { | |
| 141 | 143 | memcpy(string->chars, cstring, strlen(cstring)); | |
| 142 | 144 | string->length = strlen(cstring); | |
| 145 | + | if(null_terminated) | |
| 146 | + | string->chars[string->length] = '\0'; | |
| 143 | 147 | return string; | |
| 144 | 148 | } | |
| 145 | 149 | } | |
| 146 | 150 | ||
| 147 | - | String* from_cstring_reuse(char* cstring, size_t capacity) | |
| 151 | + | String* from_cstring_reuse(char* cstring, size_t capacity, bool null_terminated) | |
| 148 | 152 | { | |
| 149 | 153 | String* string; | |
| 150 | 154 | ||
| @@ -161,9 +165,11 @@ String* from_cstring_reuse(char* cstring, size_t capacity) | |||
|---|---|---|---|
| 161 | 165 | return string; | |
| 162 | 166 | } | |
| 163 | 167 | ||
| 164 | - | String* from_cstring_del(char* cstring) | |
| 168 | + | String* from_cstring_del(char* cstring, bool null_terminated) | |
| 165 | 169 | { | |
| 166 | - | String* ret = from_cstring(cstring); | |
| 170 | + | String* ret = from_cstring(cstring, null_terminated); | |
| 171 | + | if(!ret) | |
| 172 | + | return NULL; | |
| 167 | 173 | free(cstring); | |
| 168 | 174 | return ret; | |
| 169 | 175 | } | |
Msrc/test.c
| @@ -71,66 +71,87 @@ static void test_string(void) | |||
|---|---|---|---|
| 71 | 71 | String* string2; | |
| 72 | 72 | char* cstring; | |
| 73 | 73 | size_t tmp; | |
| 74 | + | bool truth; | |
| 74 | 75 | ||
| 75 | - | string = new_string(); | |
| 76 | + | for(truth = false; truth == false || truth == true; truth++) | |
| 77 | + | { | |
| 78 | + | string = new_string(truth); | |
| 79 | + | ||
| 80 | + | string_push(string, 'a'); | |
| 81 | + | string_push(string, 'b'); | |
| 82 | + | string_push(string, 'c'); | |
| 83 | + | string_push(string, 'd'); | |
| 84 | + | assert(string->length == 4); | |
| 85 | + | ||
| 86 | + | cstring = to_cstring(string); | |
| 87 | + | assert(strcmp(cstring, "abcd") == 0); | |
| 88 | + | free(cstring); | |
| 89 | + | ||
| 90 | + | string_remove(string, 3); | |
| 91 | + | cstring = to_cstring(string); | |
| 92 | + | assert(strcmp(cstring, "abc") == 0); | |
| 93 | + | free(cstring); | |
| 94 | + | assert(string->length == 3); | |
| 95 | + | ||
| 96 | + | string_insert(string, 0,'a'); | |
| 97 | + | cstring = to_cstring(string); | |
| 98 | + | assert(strcmp(cstring, "aabc") == 0); | |
| 99 | + | free(cstring); | |
| 100 | + | string2 = from_cstring("xyz", truth); | |
| 101 | + | ||
| 102 | + | string_concat(string,string2); | |
| 103 | + | cstring = to_cstring(string); | |
| 104 | + | assert(strcmp(cstring, "aabcxyz") == 0); | |
| 105 | + | free(cstring); | |
| 106 | + | ||
| 107 | + | delete_string(string2); | |
| 108 | + | delete_string(string); | |
| 109 | + | ||
| 110 | + | string = from_cstring("abcd", truth); | |
| 111 | + | string2 = from_cstring("cd", truth); | |
| 112 | + | assert(string_find_str(string, string2, &tmp)); | |
| 113 | + | assert(tmp == 2); | |
| 114 | + | ||
| 115 | + | delete_string(string2); | |
| 116 | + | delete_string(string); | |
| 117 | + | ||
| 118 | + | string = from_cstring("abcd", truth); | |
| 119 | + | assert(string->length == 4); | |
| 120 | + | string_remove_range(string, 0, string->length); | |
| 121 | + | assert(string->length == 0); | |
| 122 | + | delete_string(string); | |
| 123 | + | ||
| 124 | + | string = from_cstring("bba", truth); | |
| 125 | + | string_strip(string, 'a'); | |
| 126 | + | assert(string->length == 2); | |
| 127 | + | ||
| 128 | + | cstring = to_cstring_del(string); | |
| 129 | + | free(cstring); | |
| 130 | + | ||
| 131 | + | ||
| 132 | + | string = from_cstring("asdyx782", truth); | |
| 133 | + | string2 = from_cstring("asdyx782", truth); | |
| 134 | + | assert(string_cmp(string, string2) == 0); | |
| 135 | + | delete_string(string2); | |
| 136 | + | delete_string(string); | |
| 137 | + | } | |
| 76 | 138 | ||
| 139 | + | string = from_cstring("asdyx782", true); | |
| 77 | 140 | string_push(string, 'a'); | |
| 78 | - | string_push(string, 'b'); | |
| 79 | - | string_push(string, 'c'); | |
| 80 | - | string_push(string, 'd'); | |
| 81 | - | assert(string->length == 4); | |
| 82 | - | ||
| 83 | - | cstring = to_cstring(string); | |
| 84 | - | assert(strcmp(cstring, "abcd") == 0); | |
| 85 | - | free(cstring); | |
| 86 | - | ||
| 87 | - | string_remove(string, 3); | |
| 88 | - | cstring = to_cstring(string); | |
| 89 | - | assert(strcmp(cstring, "abc") == 0); | |
| 90 | - | free(cstring); | |
| 91 | - | assert(string->length == 3); | |
| 92 | - | ||
| 93 | - | string_insert(string, 0,'a'); | |
| 94 | - | cstring = to_cstring(string); | |
| 95 | - | assert(strcmp(cstring, "aabc") == 0); | |
| 96 | - | free(cstring); | |
| 97 | - | ||
| 98 | - | string2 = from_cstring("xyz"); | |
| 99 | - | ||
| 100 | - | string_concat(string,string2); | |
| 101 | - | cstring = to_cstring(string); | |
| 102 | - | assert(strcmp(cstring, "aabcxyz") == 0); | |
| 103 | - | free(cstring); | |
| 104 | - | ||
| 105 | - | delete_string(string2); | |
| 106 | - | delete_string(string); | |
| 107 | - | ||
| 108 | - | string = from_cstring("abcd"); | |
| 109 | - | string2 = from_cstring("cd"); | |
| 110 | - | assert(string_find_str(string, string2, &tmp)); | |
| 111 | - | assert(tmp == 2); | |
| 141 | + | string_remove(string, 2); | |
| 142 | + | assert(strcmp(string->chars, "asyx782a") == 0); | |
| 143 | + | string_remove_range(string, 1, 7); | |
| 144 | + | assert(strcmp(string->chars, "a") == 0); | |
| 145 | + | assert(string_pop(string) == 'a'); | |
| 146 | + | string2 = from_cstring("asdasdas", false); | |
| 147 | + | string_concat(string, string2); | |
| 148 | + | assert(strcmp(string->chars, "asdasdas") == 0); | |
| 112 | 149 | ||
| 113 | 150 | delete_string(string2); | |
| 114 | - | delete_string(string); | |
| 115 | - | ||
| 116 | - | string = from_cstring("abcd"); | |
| 117 | - | assert(string->length == 4); | |
| 118 | - | string_remove_range(string, 0, string->length); | |
| 119 | - | assert(string->length == 0); | |
| 120 | - | delete_string(string); | |
| 151 | + | string2 = from_cstring("koasä_ #", true); | |
| 152 | + | string_move(string, string2); | |
| 153 | + | assert(strcmp(string->chars, "koasä_ #") == 0); | |
| 121 | 154 | ||
| 122 | - | string = from_cstring("bba"); | |
| 123 | - | string_strip(string, 'a'); | |
| 124 | - | assert(string->length == 2); | |
| 125 | - | ||
| 126 | - | cstring = to_cstring_del(string); | |
| 127 | - | free(cstring); | |
| 128 | - | ||
| 129 | - | ||
| 130 | - | string = from_cstring("asdyx782"); | |
| 131 | - | string2 = from_cstring("asdyx782"); | |
| 132 | - | assert(string_cmp(string, string2) == 0); | |
| 133 | - | delete_string(string2); | |
| 134 | 155 | delete_string(string); | |
| 135 | 156 | } | |
| 136 | 157 | ||