Adding upstream version 4.00~pre54+dfsg.
[syslinux-debian/hramrach.git] / com32 / lib / realloc.c
blob2969e313d9d812c9196bbf5a5c316d0c8abc0ea4
1 /*
2 * realloc.c
3 */
5 #include <stdlib.h>
6 #include <string.h>
7 #include <minmax.h>
9 #include "malloc.h"
11 void *realloc(void *ptr, size_t size)
13 struct free_arena_header *ah, *nah;
14 void *newptr;
15 size_t newsize, oldsize, xsize;
17 if (!ptr)
18 return malloc(size);
20 if (size == 0) {
21 free(ptr);
22 return NULL;
25 ah = (struct free_arena_header *)
26 ((struct arena_header *)ptr - 1);
28 /* Actual size of the old block */
29 oldsize = ah->a.size;
31 /* Add the obligatory arena header, and round up */
32 newsize = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
34 if (oldsize >= newsize && newsize >= (oldsize >> 2) &&
35 oldsize - newsize < 4096) {
36 /* This allocation is close enough already. */
37 return ptr;
38 } else {
39 xsize = oldsize;
41 nah = ah->a.next;
42 if ((char *)nah == (char *)ah + ah->a.size &&
43 nah->a.type == ARENA_TYPE_FREE &&
44 oldsize + nah->a.size >= newsize) {
45 /* Merge in subsequent free block */
46 ah->a.next = nah->a.next;
47 ah->a.next->a.prev = ah;
48 nah->next_free->prev_free = nah->prev_free;
49 nah->prev_free->next_free = nah->next_free;
50 xsize = (ah->a.size += nah->a.size);
53 if (xsize >= newsize) {
54 /* We can reallocate in place */
55 if (xsize >= newsize + 2 * sizeof(struct arena_header)) {
56 /* Residual free block at end */
57 nah = (struct free_arena_header *)((char *)ah + newsize);
58 nah->a.type = ARENA_TYPE_FREE;
59 nah->a.size = xsize - newsize;
60 ah->a.size = newsize;
62 /* Insert into block list */
63 nah->a.next = ah->a.next;
64 ah->a.next = nah;
65 nah->a.next->a.prev = nah;
66 nah->a.prev = ah;
68 /* Insert into free list */
69 if (newsize > oldsize) {
70 /* Hack: this free block is in the path of a memory object
71 which has already been grown at least once. As such, put
72 it at the *end* of the freelist instead of the beginning;
73 trying to save it for future realloc()s of the same block. */
74 nah->prev_free = __malloc_head.prev_free;
75 nah->next_free = &__malloc_head;
76 __malloc_head.prev_free = nah;
77 nah->prev_free->next_free = nah;
78 } else {
79 nah->next_free = __malloc_head.next_free;
80 nah->prev_free = &__malloc_head;
81 __malloc_head.next_free = nah;
82 nah->next_free->prev_free = nah;
85 /* otherwise, use up the whole block */
86 return ptr;
87 } else {
88 /* Last resort: need to allocate a new block and copy */
89 oldsize -= sizeof(struct arena_header);
90 newptr = malloc(size);
91 if (newptr) {
92 memcpy(newptr, ptr, min(size, oldsize));
93 free(ptr);
95 return newptr;