mirror of
https://github.com/tailix/libkernaux.git
synced 2024-11-13 11:04:27 -05:00
Implement realloc (#99)
This commit is contained in:
parent
0922a18e70
commit
f5ae8400c0
3 changed files with 203 additions and 48 deletions
|
@ -43,7 +43,6 @@
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void *KernAux_FreeList_calloc (void *malloc, size_t nmemb, size_t size);
|
|
||||||
static void KernAux_FreeList_free (void *malloc, void *ptr);
|
static void KernAux_FreeList_free (void *malloc, void *ptr);
|
||||||
static void *KernAux_FreeList_malloc (void *malloc, size_t size);
|
static void *KernAux_FreeList_malloc (void *malloc, size_t size);
|
||||||
static void *KernAux_FreeList_realloc(void *malloc, void *ptr, size_t size);
|
static void *KernAux_FreeList_realloc(void *malloc, void *ptr, size_t size);
|
||||||
|
@ -73,7 +72,7 @@ void KernAux_FreeList_init(
|
||||||
) {
|
) {
|
||||||
KERNAUX_ASSERT(free_list);
|
KERNAUX_ASSERT(free_list);
|
||||||
|
|
||||||
free_list->malloc.calloc = KernAux_FreeList_calloc;
|
free_list->malloc.calloc = NULL;
|
||||||
free_list->malloc.free = KernAux_FreeList_free;
|
free_list->malloc.free = KernAux_FreeList_free;
|
||||||
free_list->malloc.malloc = KernAux_FreeList_malloc;
|
free_list->malloc.malloc = KernAux_FreeList_malloc;
|
||||||
free_list->malloc.realloc = KernAux_FreeList_realloc;
|
free_list->malloc.realloc = KernAux_FreeList_realloc;
|
||||||
|
@ -123,35 +122,16 @@ block_found:
|
||||||
UNLOCK(free_list);
|
UNLOCK(free_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *KernAux_FreeList_calloc(
|
|
||||||
void *const malloc,
|
|
||||||
const size_t nmemb,
|
|
||||||
const size_t size
|
|
||||||
) {
|
|
||||||
KERNAUX_ASSERT(malloc);
|
|
||||||
|
|
||||||
const size_t total_size = nmemb * size;
|
|
||||||
KERNAUX_ASSERT(total_size >= nmemb);
|
|
||||||
KERNAUX_ASSERT(total_size >= size);
|
|
||||||
KERNAUX_ASSERT(total_size / nmemb == size);
|
|
||||||
|
|
||||||
void *const ptr = KernAux_FreeList_malloc(malloc, total_size);
|
|
||||||
if (ptr) memset(ptr, 0, total_size);
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KernAux_FreeList_free(void *const malloc, void *const ptr)
|
void KernAux_FreeList_free(void *const malloc, void *const ptr)
|
||||||
{
|
{
|
||||||
const KernAux_FreeList free_list = malloc;
|
const KernAux_FreeList free_list = malloc;
|
||||||
|
|
||||||
KERNAUX_ASSERT(free_list);
|
KERNAUX_ASSERT(free_list);
|
||||||
if (!ptr) return;
|
KERNAUX_ASSERT(ptr);
|
||||||
|
|
||||||
LOCK(free_list);
|
LOCK(free_list);
|
||||||
|
|
||||||
KernAux_FreeList_Node node =
|
KernAux_FreeList_Node node =
|
||||||
CONTAINER_OF(ptr, struct KernAux_FreeList_Node, block);
|
CONTAINER_OF(ptr, struct KernAux_FreeList_Node, block);
|
||||||
|
|
||||||
KernAux_FreeList_Node last_node = NULL;
|
KernAux_FreeList_Node last_node = NULL;
|
||||||
|
|
||||||
for (
|
for (
|
||||||
|
@ -183,9 +163,8 @@ block_added:
|
||||||
void *KernAux_FreeList_malloc(void *const malloc, const size_t size)
|
void *KernAux_FreeList_malloc(void *const malloc, const size_t size)
|
||||||
{
|
{
|
||||||
const KernAux_FreeList free_list = malloc;
|
const KernAux_FreeList free_list = malloc;
|
||||||
|
|
||||||
KERNAUX_ASSERT(free_list);
|
KERNAUX_ASSERT(free_list);
|
||||||
if (size == 0) return NULL;
|
KERNAUX_ASSERT(size);
|
||||||
|
|
||||||
LOCK(free_list);
|
LOCK(free_list);
|
||||||
|
|
||||||
|
@ -226,18 +205,29 @@ void *KernAux_FreeList_malloc(void *const malloc, const size_t size)
|
||||||
|
|
||||||
void *KernAux_FreeList_realloc(
|
void *KernAux_FreeList_realloc(
|
||||||
void *const malloc,
|
void *const malloc,
|
||||||
void *const ptr,
|
void *const old_ptr,
|
||||||
const size_t size
|
const size_t new_size
|
||||||
) {
|
) {
|
||||||
const KernAux_FreeList free_list = malloc;
|
const KernAux_FreeList free_list = malloc;
|
||||||
KERNAUX_ASSERT(free_list);
|
KERNAUX_ASSERT(free_list);
|
||||||
|
KERNAUX_ASSERT(old_ptr);
|
||||||
|
KERNAUX_ASSERT(new_size);
|
||||||
|
|
||||||
KERNAUX_ASSERT(0); // TODO
|
LOCK(free_list);
|
||||||
(void)free_list;
|
|
||||||
(void)ptr;
|
|
||||||
(void)size;
|
|
||||||
|
|
||||||
return NULL;
|
KernAux_FreeList_Node node =
|
||||||
|
CONTAINER_OF(old_ptr, struct KernAux_FreeList_Node, block);
|
||||||
|
const size_t old_size = node->size - NODE_HEADER_SIZE;
|
||||||
|
|
||||||
|
void *new_ptr = KernAux_FreeList_malloc(free_list, new_size);
|
||||||
|
|
||||||
|
if (new_ptr) {
|
||||||
|
const size_t min_size = old_size < new_size ? old_size : new_size;
|
||||||
|
memcpy(new_ptr, old_ptr, min_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK(free_list);
|
||||||
|
return new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_FreeList_defrag(const KernAux_FreeList free_list)
|
void KernAux_FreeList_defrag(const KernAux_FreeList free_list)
|
||||||
|
|
|
@ -6,13 +6,24 @@
|
||||||
#include <kernaux/generic/malloc.h>
|
#include <kernaux/generic/malloc.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void *KernAux_Malloc_calloc(KernAux_Malloc malloc, size_t nmemb, size_t size)
|
void *KernAux_Malloc_calloc(KernAux_Malloc malloc, size_t nmemb, size_t size)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(malloc);
|
KERNAUX_ASSERT(malloc);
|
||||||
KERNAUX_ASSERT(malloc->calloc);
|
|
||||||
|
|
||||||
return malloc->calloc((void*)malloc, nmemb, size);
|
// Common implementation
|
||||||
|
const size_t total_size = nmemb * size;
|
||||||
|
if (!total_size) return NULL;
|
||||||
|
if (total_size / nmemb != size) return NULL;
|
||||||
|
|
||||||
|
// Inherited implementation
|
||||||
|
if (malloc->calloc) return malloc->calloc((void*)malloc, nmemb, size);
|
||||||
|
|
||||||
|
// Default implementation
|
||||||
|
void *const ptr = KernAux_Malloc_malloc(malloc, total_size);
|
||||||
|
if (ptr) memset(ptr, 0, total_size);
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
|
void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
|
||||||
|
@ -20,6 +31,10 @@ void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
|
||||||
KERNAUX_ASSERT(malloc);
|
KERNAUX_ASSERT(malloc);
|
||||||
KERNAUX_ASSERT(malloc->free);
|
KERNAUX_ASSERT(malloc->free);
|
||||||
|
|
||||||
|
// Common implementation
|
||||||
|
if (!ptr) return;
|
||||||
|
|
||||||
|
// Inherited implementation
|
||||||
malloc->free((void*)malloc, ptr);
|
malloc->free((void*)malloc, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +43,10 @@ void *KernAux_Malloc_malloc(KernAux_Malloc malloc, size_t size)
|
||||||
KERNAUX_ASSERT(malloc);
|
KERNAUX_ASSERT(malloc);
|
||||||
KERNAUX_ASSERT(malloc->malloc);
|
KERNAUX_ASSERT(malloc->malloc);
|
||||||
|
|
||||||
|
// Common implementation
|
||||||
|
if (!size) return NULL;
|
||||||
|
|
||||||
|
// Inherited implementation
|
||||||
return malloc->malloc((void*)malloc, size);
|
return malloc->malloc((void*)malloc, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,5 +55,13 @@ void *KernAux_Malloc_realloc(KernAux_Malloc malloc, void *ptr, size_t size)
|
||||||
KERNAUX_ASSERT(malloc);
|
KERNAUX_ASSERT(malloc);
|
||||||
KERNAUX_ASSERT(malloc->realloc);
|
KERNAUX_ASSERT(malloc->realloc);
|
||||||
|
|
||||||
|
// Common implementation
|
||||||
|
if (!ptr) return KernAux_Malloc_malloc(malloc, size);
|
||||||
|
if (!size) {
|
||||||
|
KernAux_Malloc_free(malloc, ptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherited implementation
|
||||||
return malloc->realloc((void*)malloc, ptr, size);
|
return malloc->realloc((void*)malloc, ptr, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,55 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void test_default();
|
static void test_default();
|
||||||
|
static void test_cross_zone_defrag();
|
||||||
|
|
||||||
static void test_calloc();
|
static void test_calloc();
|
||||||
static void test_calloc_nomem();
|
static void test_calloc_nomem();
|
||||||
static void test_cross_zone_defrag();
|
static void test_calloc_overflow();
|
||||||
|
static void test_calloc_zero();
|
||||||
|
|
||||||
|
static void test_realloc_alloc();
|
||||||
|
static void test_realloc_free();
|
||||||
|
static void test_realloc_memcpy();
|
||||||
|
static void test_realloc_increase();
|
||||||
|
static void test_realloc_decrease();
|
||||||
|
|
||||||
|
static size_t nodes_count(KernAux_FreeList free_list);
|
||||||
|
|
||||||
|
static const char *const hello = "Hello, World!";
|
||||||
|
|
||||||
void test_main()
|
void test_main()
|
||||||
{
|
{
|
||||||
test_default();
|
test_default();
|
||||||
|
test_cross_zone_defrag();
|
||||||
|
|
||||||
test_calloc();
|
test_calloc();
|
||||||
test_calloc_nomem();
|
test_calloc_nomem();
|
||||||
test_cross_zone_defrag();
|
test_calloc_overflow();
|
||||||
|
test_calloc_zero();
|
||||||
|
|
||||||
|
test_realloc_alloc();
|
||||||
|
test_realloc_free();
|
||||||
|
test_realloc_memcpy();
|
||||||
|
test_realloc_increase();
|
||||||
|
test_realloc_decrease();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nodes_count(const KernAux_FreeList free_list)
|
||||||
|
{
|
||||||
|
size_t nodes_count = 0;
|
||||||
|
for (
|
||||||
|
KernAux_FreeList_Node item_node = free_list->head;
|
||||||
|
item_node;
|
||||||
|
item_node = item_node->next
|
||||||
|
) {
|
||||||
|
++nodes_count;
|
||||||
|
}
|
||||||
|
return nodes_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_default()
|
void test_default()
|
||||||
|
@ -65,6 +101,16 @@ void test_default()
|
||||||
assert(ptr7 == ptr2);
|
assert(ptr7 == ptr2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_cross_zone_defrag()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, &zone[0], 500);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, &zone[500], 500);
|
||||||
|
|
||||||
|
assert(nodes_count(&free_list) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
void test_calloc()
|
void test_calloc()
|
||||||
{
|
{
|
||||||
char zone[1000];
|
char zone[1000];
|
||||||
|
@ -86,21 +132,113 @@ void test_calloc_nomem()
|
||||||
assert(ptr == NULL);
|
assert(ptr == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cross_zone_defrag()
|
void test_calloc_overflow()
|
||||||
{
|
{
|
||||||
char zone[1000];
|
char zone[1000];
|
||||||
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
KernAux_FreeList_add_zone(&free_list, &zone[0], 500);
|
KernAux_FreeList_add_zone(&free_list, zone, SIZE_MAX);
|
||||||
KernAux_FreeList_add_zone(&free_list, &zone[500], 500);
|
{
|
||||||
|
void *const ptr = KernAux_Malloc_calloc(&free_list.malloc, 2, SIZE_MAX);
|
||||||
size_t nodes_count = 0;
|
assert(ptr == NULL);
|
||||||
for (
|
}
|
||||||
KernAux_FreeList_Node item_node = free_list.head;
|
{
|
||||||
item_node;
|
void *const ptr = KernAux_Malloc_calloc(&free_list.malloc, SIZE_MAX, 2);
|
||||||
item_node = item_node->next
|
assert(ptr == NULL);
|
||||||
) {
|
|
||||||
++nodes_count;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
assert(nodes_count == 1);
|
|
||||||
|
void test_calloc_zero()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
|
||||||
|
void *const ptr1 = KernAux_Malloc_calloc(&free_list.malloc, 0, 900);
|
||||||
|
assert(ptr1 == NULL);
|
||||||
|
void *const ptr2 = KernAux_Malloc_calloc(&free_list.malloc, 900, 0);
|
||||||
|
assert(ptr2 == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc_alloc()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
|
||||||
|
void *const ptr = KernAux_Malloc_realloc(&free_list.malloc, NULL, 900);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc_free()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
|
||||||
|
|
||||||
|
void *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 900);
|
||||||
|
assert(ptr1 != NULL);
|
||||||
|
|
||||||
|
void *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 0);
|
||||||
|
assert(ptr2 == NULL);
|
||||||
|
|
||||||
|
void *const ptr3 = KernAux_Malloc_malloc(&free_list.malloc, 900);
|
||||||
|
assert(ptr3 != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc_memcpy()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
|
||||||
|
|
||||||
|
char *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 400);
|
||||||
|
assert(ptr1 != NULL);
|
||||||
|
|
||||||
|
memset(ptr1, 0, 400);
|
||||||
|
strcpy(ptr1, hello);
|
||||||
|
strcpy(&ptr1[400 - strlen(hello) - 1], hello);
|
||||||
|
|
||||||
|
char *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 400);
|
||||||
|
assert(ptr2 != NULL);
|
||||||
|
|
||||||
|
assert(strcmp(ptr2, hello) == 0);
|
||||||
|
assert(strcmp(&ptr2[400 - strlen(hello) - 1], hello) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc_increase()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
|
||||||
|
|
||||||
|
char *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 300);
|
||||||
|
assert(ptr1 != NULL);
|
||||||
|
|
||||||
|
memset(ptr1, 0, 300);
|
||||||
|
strcpy(ptr1, hello);
|
||||||
|
strcpy(&ptr1[300 - strlen(hello) - 1], hello);
|
||||||
|
|
||||||
|
char *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 500);
|
||||||
|
assert(ptr2 != NULL);
|
||||||
|
|
||||||
|
assert(strcmp(ptr2, hello) == 0);
|
||||||
|
assert(strcmp(&ptr2[300 - strlen(hello) - 1], hello) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_realloc_decrease()
|
||||||
|
{
|
||||||
|
char zone[1000];
|
||||||
|
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
|
||||||
|
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
|
||||||
|
|
||||||
|
char *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 500);
|
||||||
|
assert(ptr1 != NULL);
|
||||||
|
|
||||||
|
memset(ptr1, 0, 300);
|
||||||
|
strcpy(ptr1, hello);
|
||||||
|
strcpy(&ptr1[300 - strlen(hello) - 1], hello);
|
||||||
|
|
||||||
|
char *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 300);
|
||||||
|
assert(ptr2 != NULL);
|
||||||
|
|
||||||
|
assert(strcmp(ptr2, hello) == 0);
|
||||||
|
assert(strcmp(&ptr2[300 - strlen(hello) - 1], hello) == 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue