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
|
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "common/strpool.h"
struct sfdo_strpool_chunk {
struct sfdo_strpool_chunk *next;
char data[];
};
#define CHUNK_MIN_SIZE (4096 - sizeof(struct sfdo_strpool_chunk) - 8)
const char *sfdo_strpool_add(struct sfdo_strpool *pool, const char *data, size_t len) {
if (len == 0) {
return "";
}
size_t size = len + 1;
char *out = NULL;
if (size > pool->n_free) {
size_t data_size = size > CHUNK_MIN_SIZE ? size : CHUNK_MIN_SIZE;
struct sfdo_strpool_chunk *chunk = malloc(sizeof(*chunk) + data_size);
if (chunk == NULL) {
return NULL;
}
size_t chunk_nfree = data_size - size;
if (chunk_nfree < pool->n_free) {
// Put the new chunk after head
assert(pool->chunks != NULL);
chunk->next = pool->chunks->next;
pool->chunks->next = chunk;
} else {
// The new chunk is the new head
chunk->next = pool->chunks;
pool->chunks = chunk;
pool->n_free = chunk_nfree;
}
out = chunk->data;
} else {
// If there's free space, the total size is CHUNK_MIN_SIZE
char *start = pool->chunks->data + CHUNK_MIN_SIZE - pool->n_free;
pool->n_free -= size;
out = start;
}
memcpy(out, data, len);
out[len] = '\0';
return out;
}
void sfdo_strpool_init(struct sfdo_strpool *pool) {
pool->chunks = NULL;
pool->n_free = 0;
}
void sfdo_strpool_finish(struct sfdo_strpool *pool) {
struct sfdo_strpool_chunk *chunk = pool->chunks;
while (chunk != NULL) {
struct sfdo_strpool_chunk *next = chunk->next;
free(chunk);
chunk = next;
}
}
void sfdo_strpool_save(struct sfdo_strpool *pool, struct sfdo_strpool_state *state) {
state->chunk = pool->chunks;
state->n_free = pool->n_free;
}
void sfdo_strpool_restore(struct sfdo_strpool *pool, struct sfdo_strpool_state *state) {
struct sfdo_strpool_chunk *chunk = pool->chunks;
while (chunk != state->chunk) {
struct sfdo_strpool_chunk *next = chunk->next;
free(chunk);
chunk = next;
}
pool->chunks = chunk;
pool->n_free = state->n_free;
}
|