/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
#include
#include
#include
#include
typedef struct Link
{
struct Link *prev, *next;
} Link;
typedef struct MemHeader
{
Link sibling;
Link child;
void (*destruct) (void* data);
} MemHeader;
#define OFFSET(type, field) ((char*) &((type*)0)->field - (char*) 0)
#define LINK_STRUCT(link, type, field) ((void*) ((char*) link - OFFSET(type, field)))
static void
LinkInit(Link* link)
{
link->prev = link->next = link;
}
static void
LinkAppend(Link* list, Link* link)
{
list->prev->next = link;
link->prev = list->prev;
list->prev = link;
link->next = list;
}
static void
LinkRemove(Link* link)
{
Link* prev = link->prev;
Link* next = link->next;
link->prev->next = next;
link->next->prev = prev;
LinkInit(link);
}
#define ALIGNMENT 8
#define ALIGNMENT_GAP ((ALIGNMENT - sizeof(MemHeader) % ALIGNMENT) % ALIGNMENT)
#define MEM_HEADER(obj) ((MemHeader*) ((char*) obj - ALIGNMENT_GAP - sizeof(MemHeader)))
#define MEM_CONTENT(hdr) ((void*) ((char*) hdr + ALIGNMENT_GAP + sizeof(MemHeader)))
void*
talloc (void* ctx, size_t size, void (*destruct)(void*))
{
size_t gapsize = ALIGNMENT_GAP;
size_t addedsize = size + sizeof(MemHeader) + gapsize;
MemHeader* context = ctx ? MEM_HEADER(ctx) : NULL;
MemHeader* obj = malloc(addedsize);
if (!obj)
{
return NULL;
}
LinkInit(&obj->child);
LinkInit(&obj->sibling);
obj->destruct = destruct;
if (!obj->destruct)
obj->destruct = tfree_children;
if (context)
{
LinkAppend(&context->child, &obj->sibling);
}
return MEM_CONTENT(obj);
}
void*
trealloc (void *obj, size_t newsize)
{
size_t gapsize = ALIGNMENT_GAP;
size_t addedsize = newsize + sizeof(MemHeader) + gapsize;
MemHeader* hdr = MEM_HEADER(obj);
hdr = realloc(hdr, addedsize);
if (!hdr)
{
return NULL;
}
return MEM_CONTENT(hdr);
}
void
tfree (void* obj)
{
MemHeader* hdr = MEM_HEADER(obj);
LinkRemove(&hdr->sibling);
if (hdr->destruct)
hdr->destruct(obj);
memset(hdr, 0, sizeof(*hdr));
free(hdr);
}
void
tfree_children(void* obj)
{
MemHeader* hdr = MEM_HEADER(obj);
while (hdr->child.next != &hdr->child)
tfree(MEM_CONTENT(LINK_STRUCT(hdr->child.next, MemHeader, sibling)));
}
void
tunlink_children(void* obj)
{
MemHeader* hdr = MEM_HEADER(obj);
Link* child, *next;
for (child = hdr->child.next; child != &hdr->child; child = next)
{
next = child->next;
LinkInit(child);
}
LinkInit(&hdr->child);
}
void *
tdup (void* ctx, void *src, size_t size, void (*destruct)(void*))
{
void* result = talloc(ctx, size, destruct);
if (!result)
{
return NULL;
}
memcpy(result, src, size);
return result;
}
void
tlink(void* parent, void* child)
{
MemHeader* phdr = MEM_HEADER(parent);
MemHeader* chdr = MEM_HEADER(child);
LinkRemove(&chdr->sibling);
LinkAppend(&phdr->child, &chdr->sibling);
}
void
tunlink(void* child)
{
MemHeader* chdr = MEM_HEADER(child);
LinkRemove(&chdr->child);
}
/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/