开始设计
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
#include <c_StringBuffer.h>
|
||||
#include <c_Memory.h>
|
||||
|
||||
#define DEFAULT_INIT_CAPACITY 16
|
||||
|
||||
C_STATIC_FORCE_INLINE
|
||||
c_err_t c_StringBuffer_EnsureCapacity(c_StringBuffer_t* self, c_size_t required_len) {
|
||||
c_size_t needed_capacity = self->size + required_len + 1; // +1 for trailing '\0'
|
||||
if (needed_capacity <= self->capacity) {
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_size_t new_capacity = self->capacity == 0 ? DEFAULT_INIT_CAPACITY : self->capacity;
|
||||
while (new_capacity < needed_capacity) {
|
||||
new_capacity *= 2; // Exponential doubling strategy
|
||||
}
|
||||
|
||||
char* new_buffer = (char*)C_ALLOC(new_capacity);
|
||||
if (!new_buffer) {
|
||||
return C_ERR_NOMEM;
|
||||
}
|
||||
|
||||
if (self->buffer && self->size > 0) {
|
||||
memcpy(new_buffer, self->buffer, self->size);
|
||||
}
|
||||
new_buffer[self->size] = '\0';
|
||||
|
||||
C_FREE(self->buffer);
|
||||
self->buffer = new_buffer;
|
||||
self->capacity = new_capacity;
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
c_err_t c_StringBuffer_Init(c_StringBuffer_t* self, c_size_t capacity) {
|
||||
if (!self) return C_ERR_PARAM;
|
||||
|
||||
self->size = 0;
|
||||
self->capacity = capacity > 0 ? capacity : DEFAULT_INIT_CAPACITY; // Enforce minimum initial allocation
|
||||
self->buffer = (char*)C_ALLOC(self->capacity);
|
||||
if (!self->buffer) {
|
||||
self->capacity = 0;
|
||||
return C_ERR_NOMEM;
|
||||
}
|
||||
self->buffer[0] = '\0';
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
void c_StringBuffer_Destroy(c_StringBuffer_t* self) {
|
||||
if (!self) return;
|
||||
if (self->buffer) {
|
||||
C_FREE(self->buffer);
|
||||
}
|
||||
self->size = 0;
|
||||
self->capacity = 0;
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_Append(c_StringBuffer_t* self, const char* string, c_size_t length) {
|
||||
if (!self || !self->buffer || !string || length == 0) return C_ERR_PARAM;
|
||||
|
||||
c_err_t err = c_StringBuffer_EnsureCapacity(self, length);
|
||||
if (err != C_ERR_OK) return err;
|
||||
|
||||
memcpy(self->buffer + self->size, string, length);
|
||||
self->size += length;
|
||||
self->buffer[self->size] = '\0';
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_Prepend(c_StringBuffer_t* self, const char* string, c_size_t length) {
|
||||
return c_StringBuffer_InsertAt(self, 0, string, length);
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_InsertAt(c_StringBuffer_t* self, c_size_t index, const char* string, c_size_t length) {
|
||||
if (!self || !self->buffer || !string || length == 0 || index > self->size) return C_ERR_PARAM;
|
||||
|
||||
c_err_t err = c_StringBuffer_EnsureCapacity(self, length);
|
||||
if (err != C_ERR_OK) return err;
|
||||
|
||||
// Shift memory to the right using memmove to prevent overlapping issues
|
||||
memmove(self->buffer + index + length, self->buffer + index, self->size - index);
|
||||
memcpy(self->buffer + index, string, length);
|
||||
|
||||
self->size += length;
|
||||
self->buffer[self->size] = '\0';
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_RemoveAt(c_StringBuffer_t* self, c_size_t index, c_size_t length) {
|
||||
if (!self || !self->buffer || length == 0 || index >= self->size) return C_ERR_PARAM;
|
||||
|
||||
// Clamp length if it attempts to read past the end of the current buffer
|
||||
if (index + length > self->size) {
|
||||
length = self->size - index;
|
||||
}
|
||||
|
||||
// Shift trailing memory to the left to close the character gap
|
||||
memmove(self->buffer + index, self->buffer + index + length, self->size - (index + length));
|
||||
self->size -= length;
|
||||
self->buffer[self->size] = '\0';
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
void c_StringBuffer_Clear(c_StringBuffer_t* self) {
|
||||
if (!self || !self->buffer) return;
|
||||
self->size = 0;
|
||||
self->buffer[0] = '\0';
|
||||
}
|
||||
|
||||
/* --- Explicit String-Wrapper Interfaces --- */
|
||||
|
||||
c_err_t c_StringBuffer_AppendStr(c_StringBuffer_t* self, const char* string) {
|
||||
if (!string) return C_ERR_PARAM;
|
||||
return c_StringBuffer_Append(self, string, strlen(string));
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_PrependStr(c_StringBuffer_t* self, const char* string) {
|
||||
if (!string) return C_ERR_PARAM;
|
||||
return c_StringBuffer_Prepend(self, string, strlen(string));
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c_size_t index) {
|
||||
if (!string) return C_ERR_PARAM;
|
||||
return c_StringBuffer_InsertAt(self, index, string, strlen(string));
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t length, char* buffer, c_size_t buffer_length) {
|
||||
// 1. Guard against invalid pointers, empty destinations, or index out-of-bounds
|
||||
if (!self || !self->buffer || !buffer || buffer_length == 0 || index > self->size) {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
|
||||
// 2. Clamp requested copy length if it exceeds the remaining data payload bounds
|
||||
if (index + length > self->size) {
|
||||
length = self->size - index;
|
||||
}
|
||||
|
||||
// 3. Enforce destination buffer capacity threshold checks
|
||||
// The requested segment requires at least (length + 1) bytes for safe null-termination
|
||||
if (length >= buffer_length) {
|
||||
return C_ERR_PARAM; // Destination buffer is too small to store the segment safely
|
||||
}
|
||||
|
||||
// 4. Perform the raw memory copy if there are valid characters to process
|
||||
if (length > 0) {
|
||||
memcpy(buffer, self->buffer + index, length);
|
||||
}
|
||||
|
||||
// 5. Always apply a deterministic trailing null terminator
|
||||
buffer[length] = '\0';
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user