1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#include "../include/extract_alloc.h"
#include "memento.h"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
struct extract_alloc_t
{
extract_realloc_fn_t realloc_fn;
void* realloc_state;
size_t exp_min_alloc_size;
extract_alloc_stats_t stats;
};
int extract_alloc_create(extract_realloc_fn_t realloc_fn, void* realloc_state, extract_alloc_t** palloc)
{
assert(realloc_fn);
assert(palloc);
*palloc = realloc_fn(realloc_state, NULL /*ptr*/, sizeof(**palloc));
if (!*palloc) {
errno = ENOMEM;
return -1;
}
memset(*palloc, 0, sizeof(**palloc));
(*palloc)->realloc_fn = realloc_fn;
(*palloc)->realloc_state = realloc_state;
(*palloc)->exp_min_alloc_size = 0;
return 0;
}
void extract_alloc_destroy(extract_alloc_t** palloc)
{
if (!*palloc) return;
(*palloc)->realloc_fn((*palloc)->realloc_state, *palloc, 0 /*newsize*/);
*palloc = NULL;
}
extract_alloc_stats_t* extract_alloc_stats(extract_alloc_t* alloc)
{
return &alloc->stats;
}
static size_t round_up(extract_alloc_t* alloc, size_t n)
{
if (alloc && alloc->exp_min_alloc_size) {
/* Round up to power of two. */
size_t ret;
if (n==0) return 0;
ret = alloc->exp_min_alloc_size;
for(;;) {
size_t ret_old;
if (ret >= n) return ret;
ret_old = ret;
ret *= 2;
assert(ret > ret_old);
(void) ret_old;
}
}
else {
return n;
}
}
int (extract_malloc)(extract_alloc_t* alloc, void** pptr, size_t size)
{
void* p;
size = round_up(alloc, size);
p = (alloc) ? alloc->realloc_fn(alloc->realloc_state, NULL, size) : malloc(size);
*pptr = p;
if (!p && size)
{
if (alloc) errno = ENOMEM;
return -1;
}
if (alloc) alloc->stats.num_malloc += 1;
return 0;
}
int (extract_realloc)(extract_alloc_t* alloc, void** pptr, size_t newsize)
{
void* p = (alloc) ? alloc->realloc_fn(alloc->realloc_state, *pptr, newsize) : realloc(*pptr, newsize);
if (!p && newsize)
{
if (alloc) errno = ENOMEM;
return -1;
}
*pptr = p;
if (alloc) alloc->stats.num_realloc += 1;
return 0;
}
int (extract_realloc2)(extract_alloc_t* alloc, void** pptr, size_t oldsize, size_t newsize)
{
/* We ignore <oldsize> if <ptr> is NULL - allows callers to not worry about
edge cases e.g. with strlen+1. */
oldsize = (*pptr) ? round_up(alloc, oldsize) : 0;
newsize = round_up(alloc, newsize);
if (newsize == oldsize) return 0;
return (extract_realloc)(alloc, pptr, newsize);
}
void (extract_free)(extract_alloc_t* alloc, void** pptr)
{
if (alloc) {
(void) alloc->realloc_fn(alloc->realloc_state, *pptr, 0);
}
else {
free(*pptr);
}
*pptr = NULL;
if (alloc) alloc->stats.num_free += 1;
}
void extract_alloc_exp_min(extract_alloc_t* alloc, size_t size)
{
alloc->exp_min_alloc_size = size;
}
|