view src/dmgrowbuf.c @ 1536:064fc2e3ee64

Add compile-time debugging information to DMGrowBuf.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 12 May 2018 04:12:46 +0300
parents 260bf529a8f2
children 383ca5f6e78b
line wrap: on
line source

/*
 * DMLib
 * -- Growable buffer implementation
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2018 Tecnic Software productions (TNSP)
 */
#include "dmgrowbuf.h"

//#define DM_GROWBUF_DEBUG 1

#ifdef DM_GROWBUF_DEBUG
#    define DM_DBG(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
#else
#    define DM_DBG(...) do { } while (0)
#endif


int dmGrowBufInit(DMGrowBuf *buf)
{
    DM_DBG("dmGrowBufInit(%p)\n", buf);
    if (buf == NULL)
        return DMERR_NULLPTR;

    memset(buf, 0, sizeof(DMGrowBuf));

    return DMERR_OK;
}


int dmGrowBufAlloc(DMGrowBuf *buf, const size_t initial, const size_t mingrow)
{
    int res;

    DM_DBG("dmGrowBufAlloc(%p, %" DM_PRIu_SIZE_T ", %" DM_PRIu_SIZE_T ")\n", buf, initial, mingrow);
    if ((res = dmGrowBufInit(buf)) != DMERR_OK)
        return res;

    buf->len  = 0;
    buf->offs = 0;
    buf->size = initial;
    buf->mingrow = mingrow;
    buf->allocated = FALSE;

    // Allocate the data
    if ((buf->adata = buf->data = dmMalloc0(initial)) == NULL)
        return DMERR_MALLOC;

    return DMERR_OK;
}


int dmGrowBufNew(DMGrowBuf **pbuf, const size_t initial, const size_t mingrow)
{
    int res;
    if (pbuf == NULL)
        return DMERR_NULLPTR;

    DM_DBG("dmGrowBufNew(%p, %" DM_PRIu_SIZE_T ", %" DM_PRIu_SIZE_T ")\n", pbuf, initial, mingrow);
    if ((*pbuf = dmMalloc0(sizeof(DMGrowBuf))) == NULL)
        return DMERR_MALLOC;

    if ((res = dmGrowBufAlloc(*pbuf, initial, mingrow)) != DMERR_OK)
    {
        // The "allocated" flag has not yet been set
        dmGrowBufFree(*pbuf);

        // .. thus free the allocated struct here
        dmFreeR(pbuf);
        return res;
    }

    (*pbuf)->allocated = TRUE;
    return res;
}


void dmGrowBufFree(DMGrowBuf *buf)
{
    DM_DBG("dmGrowBufFree(%p)\n", buf);
    if (buf != NULL)
    {
        DM_DBG(
            "      buf->adata      = %p\n"
            "      buf->data       = %p\n"
            "      buf->allocated  = %s\n",
            buf->adata, buf->data, buf->allocated ? "YES" : "NO"); 

        dmFreeR(&buf->adata);
        buf->data = NULL;

        if (buf->allocated)
            dmFree(buf);
    }
}


void dmGrowBufPush(DMGrowBuf *buf)
{
    if (buf != NULL && buf->adata != NULL)
    {
        DM_DBG("dmGrowBufPush(%p): size=%" DM_PRIu_SIZE_T "\n"
            "    nstack=%d [offs=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T "]\n", buf, buf->size, buf->nstack, buf->offs, buf->len);

        buf->stack[buf->nstack].offs = buf->offs;
        buf->stack[buf->nstack].len = buf->len;
        buf->nstack++;

        buf->offs = buf->len;
        buf->data = buf->adata + buf->offs;
        buf->len  = 0;

        DM_DBG(
            "    nstack=%d [offs=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T "]\n", buf->nstack, buf->offs, buf->len);
    }
    else
        DM_DBG("dmGrowBufPush(%p)\n", buf);
}


void dmGrowBufPop(DMGrowBuf *buf)
{
    if (buf != NULL && buf->adata != NULL && buf->nstack > 0)
    {
        DM_DBG("dmGrowBufPop(%p): size=%" DM_PRIu_SIZE_T "\n"
            "    nstack=%d [offs=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T "]\n", buf, buf->size, buf->nstack, buf->offs, buf->len);

        buf->nstack--;
        buf->offs  = buf->stack[buf->nstack].offs;
        buf->len  += buf->stack[buf->nstack].len;

        buf->data = buf->adata + buf->offs;

        DM_DBG(
            "    nstack=%d [offs=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T "]\n", buf->nstack, buf->offs, buf->len);

    }
    else
        DM_DBG("dmGrowBufPop(%p)\n", buf);
}


static BOOL dmGrowBufRealloc(DMGrowBuf *buf, const size_t nsize, const BOOL clear)
{
    DM_DBG("dmGrowBufRealloc(%p): size=%" DM_PRIu_SIZE_T "\n"
        "    nstack=%d [offs=%" DM_PRIu_SIZE_T ", len=%" DM_PRIu_SIZE_T "]\n",
        buf, buf->size, buf->nstack, buf->offs, buf->len);

    if ((buf->adata = dmRealloc(buf->adata, nsize)) == NULL)
        return FALSE;

    if (clear)
        memset(buf->adata + buf->size, 0, nsize - buf->size);

    buf->data = buf->adata + buf->offs;
    buf->size = nsize;

    return TRUE;
}


//
// Grow the buffer by "amount" bytes, but at least by buf->mingrow,
// if there is not enough space for at least that amount compared to
// current buffer "len".
//
BOOL dmGrowBufGrow(DMGrowBuf *buf, const size_t amount)
{
    if (buf->adata == NULL || buf->offs + buf->len + amount >= buf->size)
    {
        size_t grow = (amount > buf->mingrow) ? amount : buf->mingrow;
        if (!dmGrowBufRealloc(buf, buf->offs + buf->len + grow, TRUE))
            return FALSE;
    }

    return TRUE;
}


//
// Grow the buffer if "nsize" is larger than the current buffer size.
// Buffer is enlarged to nsize + mingrow.
//
BOOL dmGrowBufCheckGrow(DMGrowBuf *buf, const size_t nsize)
{
    if (buf->adata == NULL || buf->offs + nsize > buf->size)
    {
        if (!dmGrowBufRealloc(buf, buf->offs + nsize + buf->mingrow, TRUE))
            return FALSE;
    }

    return TRUE;
}


int dmGrowBufResize(DMGrowBuf *buf)
{
    if (buf == NULL)
        return DMERR_NULLPTR;

    buf->size = buf->len;
    if (buf->len == 0)
        return DMERR_OK;

    if (!dmGrowBufRealloc(buf, buf->size, FALSE))
        return DMERR_MALLOC;

    return DMERR_OK;
}


BOOL dmGrowBufPutU8(DMGrowBuf *buf, const Uint8 value)
{
    if (!dmGrowBufGrow(buf, sizeof(Uint8)))
        return FALSE;

    buf->data[buf->len++] = value;

    return TRUE;
}


BOOL dmGrowBufPut(DMGrowBuf *buf, const void *str, const size_t len)
{
    if (str == NULL)
        return FALSE;

    if (!dmGrowBufGrow(buf, len))
        return FALSE;

    memcpy(buf->data + buf->len, str, len);
    buf->len += len;

    return TRUE;
}


BOOL dmGrowBufPutU16BE(DMGrowBuf *buf, const Uint16 val)
{
    if (!dmGrowBufGrow(buf, sizeof(Uint16)))
        return FALSE;

    buf->data[buf->len++] = (val >> 8) & 0xff;
    buf->data[buf->len++] = val & 0xff;

    return TRUE;
}


BOOL dmGrowBufPutU16LE(DMGrowBuf *buf, const Uint16 val)
{
    if (!dmGrowBufGrow(buf, sizeof(Uint16)))
        return FALSE;

    buf->data[buf->len++] = val & 0xff;
    buf->data[buf->len++] = (val >> 8) & 0xff;

    return TRUE;
}


BOOL dmGrowBufPutU32BE(DMGrowBuf *buf, const Uint32 val)
{
    if (!dmGrowBufGrow(buf, sizeof(Uint32)))
        return FALSE;

    buf->data[buf->len++] = (val >> 24) & 0xff;
    buf->data[buf->len++] = (val >> 16) & 0xff;
    buf->data[buf->len++] = (val >> 8) & 0xff;
    buf->data[buf->len++] = val & 0xff;

    return TRUE;
}


BOOL dmGrowBufPutU32LE(DMGrowBuf *buf, const Uint32 val)
{
    if (!dmGrowBufGrow(buf, sizeof(Uint32)))
        return FALSE;

    buf->data[buf->len++] = val & 0xff;
    buf->data[buf->len++] = (val >> 8) & 0xff;
    buf->data[buf->len++] = (val >> 16) & 0xff;
    buf->data[buf->len++] = (val >> 24) & 0xff;

    return TRUE;
}