Last active
June 6, 2019 00:30
-
-
Save jstimpfle/dd5466e5b2f11f2384081620f069c9e8 to your computer and use it in GitHub Desktop.
Simple string pool allocator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> // memset() | |
#include <stdlib.h> // malloc(), free() | |
enum { | |
STRINGPOOLCHUNKSIZE_16, | |
STRINGPOOLCHUNKSIZE_32, | |
STRINGPOOLCHUNKSIZE_64, | |
STRINGPOOLCHUNKSIZE_128, | |
STRINGPOOLCHUNKSIZE_256, | |
STRINGPOOLCHUNKSIZE_512, | |
NUM_STRINGPOOLCHUNKSIZE_KINDS, | |
}; | |
/* super shitty bookkeeping of allocations */ | |
struct LinkedChunk { | |
struct LinkedChunk *next; | |
char data[]; | |
}; | |
struct StringPool { | |
struct LinkedChunk *allocations; | |
struct LinkedChunk *chunksList[NUM_STRINGPOOLCHUNKSIZE_KINDS]; | |
}; | |
static const int chunksizeKindToLength[NUM_STRINGPOOLCHUNKSIZE_KINDS] = { | |
[STRINGPOOLCHUNKSIZE_16] = 16, | |
[STRINGPOOLCHUNKSIZE_32] = 32, | |
[STRINGPOOLCHUNKSIZE_64] = 64, | |
[STRINGPOOLCHUNKSIZE_128] = 128, | |
[STRINGPOOLCHUNKSIZE_256] = 256, | |
[STRINGPOOLCHUNKSIZE_512] = 512, | |
}; | |
void setup_stringpool(struct StringPool *pool) | |
{ | |
pool->allocations = NULL; | |
for (int i = 0; i < NUM_STRINGPOOLCHUNKSIZE_KINDS; i++) | |
pool->chunksList[i] = NULL; | |
} | |
void teardown_stringpool(struct StringPool *pool) | |
{ | |
struct LinkedChunk *chunk = pool->allocations; | |
while (chunk) { | |
struct LinkedChunk *next = chunk->next; | |
free(chunk); | |
chunk = next; | |
} | |
// for good hygiene | |
memset(pool, 0, sizeof *pool); | |
} | |
static void *allocate_in_pool(struct StringPool *pool, int numBytes) | |
{ | |
struct LinkedChunk *chunk = malloc(sizeof *chunk + numBytes); | |
if (chunk == NULL) | |
FATAL("OOM!\n"); | |
chunk->next = pool->allocations; | |
pool->allocations = chunk; | |
return &chunk->data[0]; // alignment? | |
} | |
static void make_chunks(struct StringPool *pool, char *data, int remainBytes) | |
{ | |
/* make smaller chunks from unused space */ | |
for (int i = NUM_STRINGPOOLCHUNKSIZE_KINDS - 1; i >= 0; i--) { | |
int thisLength = chunksizeKindToLength[i]; | |
ASSERT(remainBytes >= 0); | |
if (remainBytes >= thisLength) { | |
/* add chunk */ | |
struct LinkedChunk *unusedChunk = data + remainBytes - thisLength; | |
unusedChunk->next = pool->chunksList[i]; | |
pool->chunksList[i] = unusedChunk; | |
remainBytes -= thisLength; | |
} | |
} | |
} | |
char *alloc_in_stringpool(struct StringPool *pool, const char *text, int length) | |
{ | |
char *data = NULL; | |
int chunksizeKind; | |
/* try to find an existing StringPoolChunk of appropriate size */ | |
for (int i = 0; i < NUM_STRINGPOOLCHUNKSIZE_KINDS; i++) { | |
if (chunksizeKindToLength[i] >= length + 1) { | |
if (pool->chunksList[i] != NULL) { | |
data = (void *) pool->chunksList[i]; | |
chunksizeKind = i; | |
pool->chunksList[i] = pool->chunksList[i]->next; | |
break; | |
} | |
} | |
} | |
/* no existing chunk found. Allocate chunk. Either of largest standard size or a huge-alloc */ | |
if (data == NULL) { | |
chunksizeKind = NUM_STRINGPOOLCHUNKSIZE_KINDS - 1; | |
int numBytes = chunksizeKindToLength[chunksizeKind]; | |
if (numBytes < length + 1) { | |
/* huge-alloc */ | |
data = allocate_in_pool(pool, length + 1); | |
} | |
else { | |
/* normal alloc */ | |
data = allocate_in_pool(pool, numBytes); | |
make_chunks(pool, data + length + 1, numBytes - length - 1); | |
} | |
} | |
copy_string_and_zeroterminate(data, text, length); | |
return data; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment