HOME
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
typedef long Align; /* for alignment to long boundary */
union header { /* block header: */
struct {
union header* pnext; /* next block if on free list */
unsigned size; /* size of this block */
} s;
Align x; /* force alignment of blocks */
};
typedef union header Header;
static Header base; /* empty list to get started */
static Header* freep = NULL; /* start of free list */
Header* morecore(unsigned);
/* malloc: general-purpose storage allocator */
void* malloc2(unsigned nbytes)
{
unsigned nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
Header* prevp = freep;
if (prevp == NULL)
{ /* no free list yet */
freep = &base;
base.s.pnext = freep;
prevp = freep;
base.s.size = 0;
}
for (Header* p = prevp->s.pnext; ; prevp = p, p = p->s.pnext)
{
if (p->s.size >= nunits)
{ /* big enough */
if (p->s.size == nunits) /* exactly */
{
prevp->s.pnext = p->s.pnext;
}
else
{ /* allocate tail end */
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits;
}
freep = prevp;
return (void*)(p + 1);
}
if (p == freep) /* wrapped around free list */
{
if ((p = morecore(nunits)) == NULL)
return NULL; /* none left */
}
}
}
#define NALLOC 1024 /* minimum units to request */
void free2(void* ap);
/* morecore: ask system for more memory */
static Header* morecore(unsigned nu)
{
if (nu < NALLOC)
nu = NALLOC;
char* cp = malloc(nu * sizeof(Header));
if (cp == 0) /* no space at all */
return NULL;
Header* up = (Header*)cp;
up->s.size = nu;
free2((void*)(up + 1));
return freep;
}
/* free: put block ap in free list */
void free2(void* ap)
{
Header* p;
Header* bp = (Header*)ap - 1;
for (p = freep; !(bp > p && bp < p->s.pnext); p = p->s.pnext)
{
if (p >= p->s.pnext && (bp > p || bp < p->s.pnext))
break;
}
if (bp + bp->s.size == p->s.pnext) {
bp->s.size += p->s.pnext->s.size;
bp->s.pnext = p->s.pnext->s.pnext;
}
else {
bp->s.pnext = p->s.pnext;
}
if (p + p->s.size == bp) {
p->s.size += bp->s.size;
p->s.pnext = bp->s.pnext;
}
else {
p->s.pnext = bp;
}
freep = p;
}
struct Person {
char* name;
};
char* strdup2(const char* s)
{
int sz = strlen(s);
char* r = malloc2(sz + 1);
if (r)
memcpy(r, s, sz + 1);
return r;
}
struct Block {
struct Block* pNext;
char data[];
};
struct Allocator {
struct Block* pHead, *pTail;
unsigned bytesUsed; /*bytes used at the tail block*/
unsigned BLOCK_SIZE;
};
#define ALLOCATOR_INIT {0,0,0, 1024}
void* allocator_aligned_alloc(struct Allocator* allocator, unsigned alignment, unsigned size)
{
void* pointer = NULL;
int alignedPos = allocator->bytesUsed;
if (allocator->bytesUsed % alignment != 0)
{
/*fixing aligment*/
alignedPos = ((allocator->bytesUsed / alignment) + 1) * alignment;
}
if (allocator->pHead == NULL) {
/*creating the first block*/
struct Block* pNew =
malloc(sizeof(struct Block) + (size < allocator->BLOCK_SIZE ? allocator->BLOCK_SIZE : size));
if (pNew)
{
pNew->pNext = 0;
allocator->bytesUsed = size;
pointer = pNew->data + alignedPos;
allocator->pHead = pNew;
allocator->pTail = pNew;
}
}
else
{
if (allocator->bytesUsed < allocator->BLOCK_SIZE &&
allocator->BLOCK_SIZE - alignedPos > size)
{
/*we have space at the current tail block*/
pointer = allocator->pTail->data + alignedPos;
allocator->bytesUsed = alignedPos + size;
}
else
{
/*we dont have space at the current tail block*/
if (size > allocator->BLOCK_SIZE)
{
struct Block* pNew = malloc(sizeof(struct Block) + size);
if (pNew)
{
/*new block is created without changing the tail block*/
pNew->pNext = allocator->pHead;
allocator->pHead = pNew;
pointer = pNew + 1;
}
}
else
{
/*
new tail block is created and some memory is wasted at the previous
tail block
*/
struct Block* pNew = malloc(sizeof(struct Block) + allocator->BLOCK_SIZE);
if (pNew)
{
pNew->pNext = 0;
allocator->pTail->pNext = pNew;
pointer = pNew + 1;
allocator->bytesUsed = size;
}
}
}
}
return pointer;
}
void* allocator_malloc(struct Allocator* allocator, int sz)
{
return allocator_aligned_alloc(allocator, 8 /*default aligment*/, sz);
}
char* StrDup(struct Allocator* allocator, const char* s)
{
int sz = strlen(s);
char* r = allocator_malloc(allocator, sz + 1);
if (r)
memcpy(r, s, sz + 1);
return r;
}
void allocator_free(struct Allocator* allocator) {
for (struct Block* p = allocator->pHead; p; ) {
struct Block* temp = p;
p = p->pNext;
free(temp);
}
}
void Test1()
{
struct Allocator allocator = { .BLOCK_SIZE = 8 };
char* s = allocator_malloc(&allocator, 4);
assert(allocator.pHead != NULL);
assert(allocator.pTail != NULL);
assert(allocator.pHead == allocator.pTail);
assert(allocator.bytesUsed == 4);
allocator_free(&allocator);
}
int main()
{
struct Allocator allocator = ALLOCATOR_INIT;
char* text = 0;
text = StrDup(&allocator, "1");
text = StrDup(&allocator, "1234567890ABCD");
text = StrDup(&allocator, "test2");
allocator_free(&allocator);
}