I wrote my own C heap allocator. It probably doesn't compile because I didn't try to compile it or even briefly check for syntax errors, and even when it does compile it probably won't work without some [b][i][o][u]REFACTORING[/i][/o][/i][/b] but I'm not submitting this as an attempt to win a degree, so here it is:
/**
* \brief Allocates a block of shit.
* \param size The size of the shit-block in bytes.
* \return On success, a pointer to the shit-block is returned. On error,
* NULL is returned and errno is set to indicate the error that
* occurred.
*/
void* take_shit(size_t size);
/**
* \brief Allocates a block of shit and sets every
* \param count The number of elements in the shit-block.
* \param size The size in bytes of each shit-element.
* \return On success, a pointer to the shit-block is returned. On error,
* NULL is returned and errno is set to indicate the error that
* occurred.
*/
void* ztake_shit(size_t count, size_t size);
/**
* \brief Resizes a block of shit.
* \param shit A pointer to the shit-block to be resized.
* \param new_size The new size of the shit-block.
* \return On success, the resized shit-block is returned. On error, NULL
* is returned and errno is set to indicate the error that
* occurred.
*/
void* resize_shit(void* shit, size_t new_size);
/**
* \brief Flushes a block of shit.
* \param shit The shit-block to flush. If this is a null pointer, no action is
* performed.
* \return This function does not return a value.
*/
void flush_shit(void* shit);
#endif /* ! HEAP_OF_SHIT_H */
heapofshit.c #include <heapofshit.h>
#if defined(WINDOWS)
# include <Windows.h>
#elif defined(POSIX)
# include <unistd.h>
#endif
#ifdef POSIX
/** Stores shit-blocks. */
static struct shitblock {
void* start; /**< The start of the shit-block. */
size_t size; /**< The size of the shit-block. */
int used; /**< Whether the shit-block is in use. */
} * shitblocklist; /**< The list of shit-blocks. */
size_t num_shitblocks; /**< The number of shit-blocks in the list. */
ssize_t next_free = -1; /**< Index of the next free block. */
#endif
/**
* \brief Allocates a block of shit.
* \param size The size of the shit-block in bytes.
* \return On success, a pointer to the shit-block is returned. On error,
* NULL is returned.
*/
void* take_shit(size_t size)
{
#if defined(WINDOWS)
return HeapAlloc(GetProcessHeap(), 0, size);
#elif defined(POSIX)
if (!(shitblocklist)) {
/* Initialise the shit-block list.
*/
shitblocklist = sbrk(sizeof(*shitblocklist) * (num_shitblocks + 1));
shitblocklist[0].start = sbrk(size);
shitblocklist[0].size = size;
shitblocklist[0].used = 1;
++num_shitblocks;
return shitblocklist[0].start;
} else if ((next_free >= 0) && (size <= shitblocklist[next_free].size)) {
/* Use the next free block if it's big enough.
*/
void* p = shitblocklist[next_free].start;
shitblocklist[next_free].used = 1;
next_free = -1;
/* Cba to set next_free to the next free block because I'm /hc/.
*Besides that, it'd defeat the point of having it (which was so
* we wouldn't have to search for free blocks immediately after
* a free).
*/
return p;
} else {
/* Look for a big enough free block.
*/
void* p;
size_t i;
for (i = 0; i < num_shitblocks; ++i) {
if ((shitblocklist[i].used == 0) && (shitblocklist[i].size >= size)) {
shitblocklist[i].used = 1;
return shitblocklist[i].start;
}
}
/* If we haven't returned yet we need to take a new shit.
*/
p = sbrk(sizeof(*shitblocklist) * (num_shitblocks + 1));
if (!(p))
return NULL;
/* Copy the old list and add the new shitblock.
*/
memcpy(p, shitblocklist, sizeof(*shitblocklist) * (num_shitblocks + 1));
shitblocklist[num_shitblocks].start = sbrk(size);
shitblocklist[num_shitblocks].size = size;
shitblocklist[num_shitblocks].used = 1;
}
return NULL;
#endif
/* OH FUCK LOOK AT ALL THAT HEAP ALLOCATION I DID MAN THAT WAS NICE. */
}
/**
* \brief Allocates a block of shit and sets every
* \param count The number of elements in the shit-block.
* \param size The size in bytes of each shit-element.
* \return On success, a pointer to the shit-block is returned. On error,
* NULL is returned.
*/
void* ztake_shit(size_t count, size_t size)
{
#if defined(WINDOWS)
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
#elif defined(POSIX)
void* shit = take_shit(count * size);
if (shit)
memset(shit, 0, count * size);
return shit;
#endif
}
/**
* \brief Resizes a block of shit.
* \param shit A pointer to the shit-block to be resized.
* \param new_size The new size of the shit-block.
* \return On success, the resized shit-block is returned. On error, NULL
* is returned.
*/
void* resize_shit(void* shit, size_t new_size)
{
#if defined(WINDOWS)
return HeapReAlloc(GetProcessHeap(), shit, new_size);
#elif defined(POSIX)
void* new_shit = take_shit(new_size);
if (new_shit) {
memcpy(new_shit, shit, size);
flush_shit(shit);
}
return new_shit;
#endif
}
/**
* \brief Flushes a block of shit.
* \param shit The shit-block to flush. If this is a null pointer, no action is
* performed.
*/
void flush_shit(void* shit)
{
if (!(shit))
return;
#ifdef WINDOWS
HeapFree(GetProcessHeap(), 0, shit);
#elif defined(POSIX)
size_t i;
if (sbrk(0) == shit) {
/* Give memory at the end of the program-break back to the OS.
*/
for (i = 0; i < num_shitblocks; ++i) {
if (shitblocklist[i].start == shit) {
sbrk(0 - shitblocklist[i].size);
return;
}
}
} else {
/* Mark the block free so take_shit() can use it later.
*/
for (i = 0; i < num_shitblocks; ++i) {
if (shitblocklist[i].start == shit) {
shitblocklist[i].used = 0;
return;
}
}
}
#endif
}