/// dynamic array class /// written by: Harry Irving #include #include #include #include #include typedef struct String { uint32_t size, capacity; char* data; } String_t; int str_len(String_t* s) { return (int)s->size; } char* to_chars(String_t* s) { // allocate buffer with null terminator char* buffer = (char*)calloc(s->size + 1, sizeof(char)); for (int i = 0; i < s->size; i++) { buffer[i] = s->data[i]; } buffer[s->size] = '\0'; return buffer; } String_t str_with_capacity(int capacity) { String_t s; s.data = (char*)calloc(capacity, sizeof(char)); s.size = 0; s.capacity = capacity; return s; } String_t str_from_slice(const char* string, int len) { String_t s; s.data = (char*)calloc(len, sizeof(char)); strncpy(s.data, string, len); s.size = len; s.capacity = len; return s; } String_t str_from_chars(const char* string) { return str_from_slice(string, strlen(string)); } String_t str_new() { return str_with_capacity(1); } int str_dealloc(String_t* self) { free(self->data); return 0; } int str_push(String_t* self, char c) { if (self->size < self->capacity) { self->data[self->size] = c; self->size++; return 0; } int newcap = self->capacity + sizeof(char); self->data = (char*)realloc(self->data, newcap); self->data[self->size] = c; self->size++; self->capacity = newcap; return 0; } int str_push_str(String_t* self, char* c) { if (self->size + strlen(c) >= self->capacity) { self->capacity = (self->size + strlen(c)) * sizeof(char); self->data = (char*)realloc(self->data, self->capacity); } for (int i = 0; i < strlen(c); i++) { self->data[self->size + i] = c[i]; } self->size = self->capacity; return 0; } String_t str_from_file(FILE* file) { if (file == NULL) { return str_new(); } char buffer[64]; String_t string = str_new(); while (fgets(buffer, sizeof(buffer), file) != NULL) { str_push_str(&string, buffer); } fclose(file); return string; } int str_to_file(String_t* self, FILE* file) { char* data = to_chars(self); if (fprintf(file, "%s\n", data) == -1) { free(data); return -1; } free(data); return 0; } String_t str_clone(String_t* self) { String_t clone; clone.size = self->size; clone.capacity = self->capacity; clone.data = (char*)calloc(clone.capacity, sizeof(char)); memcpy(clone.data, self->data, clone.capacity); return clone; } String_t* str_clone_all(String_t* strings, int len) { String_t* clones = (String_t*)calloc(len, sizeof(String_t)); for (int i = 0; i < len; i++) { clones[i] = str_clone(&strings[i]); } return clones; } char str_pop(String_t* self) { if (self->size == 0) { return '\0'; } self->size--; return self->data[self->size]; } int str_insert(String_t* self, int index, char c) { if (index > self->size) { return -1; } self->size++; if (self->size > self->capacity) { self->capacity = (self->size) * sizeof(char); self->data = (char*)realloc(self->data, self->capacity); } for (int i = self->size - 1; i > index; i--) { self->data[i] = self->data[i - 1]; } self->data[index] = c; return 0; } int str_remove(String_t* self, int index) { if (index >= self->size) { return -1; } self->size--; for (int i = index; i < self->size; i++) { self->data[i] = self->data[i + 1]; } return 0; } String_t* str_split(String_t* self, int* res_len, char c) { char* string = self->data; bool flag = false; *res_len = 0; // Count number of splits for (int i = 0; i < self->size; i++) { if (string[i] == c) { (*res_len)++; flag = false; } else { flag = true; } } if (flag) { (*res_len)++; } String_t* elements = (String_t*)malloc((*res_len) * sizeof(String_t)); int i = 0; flag = false; char* start = string; char* end = string; char* string_end = string + self->size; while (end < string_end) { if (*end == c) { elements[i] = str_from_slice(start, end - start); i++; end++; start = end; flag = false; } else { end++; flag = true; } } if (flag) { elements[i] = str_from_slice(start, end - start); } return elements; } String_t str_merge(String_t* s1, String_t* s2) { String_t s; s.size = s1->size + s2->size; s.capacity = s.size; s.data = (char*)calloc(s.size, sizeof(char)); for (int i = 0; i < s1->size; i++) { s.data[i] = s1->data[i]; } for (int i = 0; i < s2->size; i++) { s.data[s1->size + i] = s2->data[i]; } return s; } String_t* str_lines(String_t* self, int* numlines) { return str_split(self, numlines, '\n'); } String_t str_slice(String_t* s, int start, int end) { String_t s2; if (start < 0) start = 0; if (end > s->size) end = s->size; // if the range is invalid, we return an empty string if (start >= end || start >= s->size) { s2.size = 0; s2.capacity = 1; s2.data = (char*)calloc(1, sizeof(char)); return s2; } s2.size = end - start; s2.capacity = s2.size; s2.data = (char*)calloc(s2.size, sizeof(char)); // if the allocation fails we return a zero sized string if (s2.data == NULL) { s2.size = 0; s2.capacity = 0; return s2; } for (int i = 0; i < s2.size; i++) { s2.data[i] = s->data[start + i]; } return s2; }