/******************************************************************************* * * Helper functions. * ******************************************************************************/ static enum sl_error ensure_allocated(struct sl_vector* vec, size_t capacity, bool keep_data) { void* buffer = NULL; enum sl_error sl_err = SL_NO_ERROR; ASSERT(vec); if(capacity > vec->capacity) { size_t new_capacity = 0; NEXT_POWER_OF_2(capacity, new_capacity); buffer = MEM_ALIGNED_ALLOC (vec->allocator, new_capacity * vec->data_size, vec->data_alignment); if(!buffer) { sl_err = SL_MEMORY_ERROR; goto error; } if(keep_data) { buffer = memcpy(buffer, vec->buffer, vec->capacity * vec->data_size); } MEM_FREE(vec->allocator, vec->buffer); vec->buffer = buffer; vec->capacity = new_capacity; buffer = NULL; } exit: return sl_err; error: if(buffer) { MEM_FREE(vec->allocator, buffer); buffer = NULL; } goto exit; }
static void regular_test(struct mem_allocator* allocator) { char dump[BUFSIZ]; void* p = NULL; void* q[3] = {NULL, NULL, NULL}; size_t i = 0; p = MEM_ALIGNED_ALLOC(allocator, 1024, ALIGNOF(char)); NCHECK(p, NULL); CHECK(IS_ALIGNED((uintptr_t)p, ALIGNOF(char)), 1); MEM_FREE(allocator, p); q[0] = MEM_ALIGNED_ALLOC(allocator, 10, 8); q[1] = MEM_CALLOC(allocator, 1, 58); q[2] = MEM_ALLOC(allocator, 78); NCHECK(q[0], NULL); NCHECK(q[1], NULL); NCHECK(q[2], NULL); CHECK(IS_ALIGNED((uintptr_t)q[0], 8), 1); p = MEM_CALLOC(allocator, 2, 2); NCHECK(p, NULL); for(i = 0; i < 4; ++i) CHECK(((char*)p)[i], 0); for(i = 0; i < 4; ++i) ((char*)p)[i] = (char)i; MEM_DUMP(allocator, dump, BUFSIZ); printf("dump:\n%s\n", dump); MEM_DUMP(allocator, dump, 16); printf("truncated dump:\n%s\n", dump); MEM_DUMP(allocator, NULL, 0); /* may not crashed. */ MEM_FREE(allocator, q[1]); p = MEM_REALLOC(allocator, p, 8); for(i = 0; i < 4; ++i) CHECK(((char*)p)[i], (char)i); for(i = 4; i < 8; ++i) ((char*)p)[i] = (char)i; MEM_FREE(allocator, q[2]); p = MEM_REALLOC(allocator, p, 5); for(i = 0; i < 5; ++i) CHECK(((char*)p)[i], (char)i); MEM_FREE(allocator, p); p = NULL; p = MEM_REALLOC(allocator, NULL, 16); NCHECK(p, NULL); p = MEM_REALLOC(allocator, p, 0); MEM_FREE(allocator, q[0]); CHECK(MEM_ALIGNED_ALLOC(allocator, 1024, 0), NULL); CHECK(MEM_ALIGNED_ALLOC(allocator, 1024, 3), NULL); CHECK(MEM_ALLOCATED_SIZE(allocator), 0); }
EXPORT_SYM enum sl_error sl_vector_insert_n (struct sl_vector* vec, size_t id, size_t count, const void* data) { void* buffer = NULL; const void* src = NULL; void* dst = NULL; size_t i = 0; enum sl_error err = SL_NO_ERROR; if(!vec || (id > vec->length) || !data) { err = SL_INVALID_ARGUMENT; goto error; } if(0 == count) { goto exit; } if(!IS_ALIGNED(data, vec->data_alignment)) { err = SL_ALIGNMENT_ERROR; goto error; } if(vec->length == SIZE_MAX) { err = SL_OVERFLOW_ERROR; goto error; } if(id == vec->length) { err = ensure_allocated(vec, vec->length + count, true); if(err != SL_NO_ERROR) goto error; dst = (void*)((uintptr_t)(vec->buffer) + vec->data_size * id); src = data; for(i = 0; i < count; ++i) { dst = memcpy(dst, src, vec->data_size); dst = (void*)((uintptr_t)(dst) + vec->data_size); } } else { if(vec->length + count >= vec->capacity) { size_t new_capacity = 0; NEXT_POWER_OF_2(vec->length + count, new_capacity); buffer = MEM_ALIGNED_ALLOC (vec->allocator, new_capacity * vec->data_size, vec->data_alignment); if(!buffer) { err = SL_MEMORY_ERROR; goto error; } /* Copy the vector data ranging from [0, id[ into the new buffer. */ if(id > 0) memcpy(buffer, vec->buffer, vec->data_size * id); if(id < vec->length) { /* Copy from the vector data [id, length[ to the new buffer * [id+count, length + count[. */ src = (void*)((uintptr_t)(vec->buffer) + vec->data_size * id); dst = (void*)((uintptr_t)(buffer) + vec->data_size * (id + count)); dst = memcpy(dst, src, vec->data_size * (vec->length - id)); } /* Set the src/dst pointer of the data insertion process. */ dst = (void*)((uintptr_t)(buffer) + vec->data_size * id); src = data; for(i = 0; i < count; ++i) { dst = memcpy(dst, src, vec->data_size); dst = (void*)((uintptr_t)(dst) + vec->data_size); } /* The data to insert may be contained in vec, i.e. free vec->buffer * *AFTER* the insertion. */ if(vec->buffer) MEM_FREE(vec->allocator, vec->buffer); vec->buffer = buffer; vec->capacity = new_capacity; buffer = NULL; } else { if(id < vec->length) { src = (void*)((uintptr_t)(vec->buffer) + vec->data_size * id); dst = (void*)((uintptr_t)(vec->buffer) + vec->data_size * (id + count)); dst = memmove(dst, src, vec->data_size * (vec->length - id)); } /* Set the src/dst pointer of the data insertion process. Note that If the * data to insert lies in the vector range [id, vec.length[ then it was * previously memoved. Its new address is offseted by count * data_size * bytes. */ dst = (void*)((uintptr_t)(vec->buffer) + vec->data_size * id); if(IS_MEMORY_OVERLAPPED (data, vec->data_size, (void*)((uintptr_t)(vec->buffer) + vec->data_size * id), (vec->length - id) * vec->data_size)) { src = (void*)((uintptr_t)data + count * vec->data_size); } else { src = data; } for(i = 0; i < count; ++i) { dst = memcpy(dst, src, vec->data_size); dst = (void*)((uintptr_t)(dst) + vec->data_size); } } } vec->length += count; exit: return err; error: if(buffer) MEM_FREE(vec->allocator, buffer); goto exit; }