%% options
copyright owner = Dirk Krause
copyright year = 2015-xxxx
license = bsd
%% header
/** @file dk4membuf.h Memory buffer.
*/
#ifndef DK4ERROR_H_INCLUDED
#include "dk4error.h"
#endif
/** One cell of a memory buffer.
*/
typedef struct _dk4_membuf_cell_t_ {
struct _dk4_membuf_cell_t_ *next; /**< Next element in linked list. */
char *buf; /**< Buffer for data storage. */
size_t max; /**< Number of bytes available. */
size_t used; /**< Number of bytes used. */
} dk4_membuf_cell_t;
/** Memory buffer object.
*/
typedef struct {
dk4_membuf_cell_t *first; /**< First cell (head of list). */
dk4_membuf_cell_t *last; /**< Last cell (end of list). */
int he; /**< Flag: Had allocation error. */
} dk4_membuf_t;
#ifdef __cplusplus
extern "C" {
#endif
/** Create new buffer, allocate initial memory.
@param erp Error report, may be NULL.
@return Pointer on success, NULL on error.
*/
dk4_membuf_t *
dk4membuf_open(dk4_er_t *erp);
/** Destroy buffer, release memory.
@param mbptr Buffer to destroy.
*/
void
dk4membuf_close(dk4_membuf_t *mbptr);
/** Store data in buffer.
@param mbptr Buffer object.
@param src Address of data to store.
@param sz Number of bytes to store.
@param erp Error report, may be NULL.
@return 1 on success, 0 on error.
Error code:
- DK4_E_INVALID_ARGUMENTS
if mbptr or src is NULL or sz is 0,
- DK4_E_MATH_OVERFLOW
if a mathematical overflow occured in size calculation,
- DK4_E_MEMORY_ALLOCATION_FAILED
with mem.elsize and mem.nelem set
if there is not enough memory available.
*/
int
dk4membuf_store(dk4_membuf_t *mbptr, const void *src, size_t sz, dk4_er_t *erp);
/** Retrieve size of data stored in memory buffer.
@param szptr Address of result variable.
@param mbptr Buffer to find size for.
@param erp Error report, may be NULL.
@return 1 on success, 0 on error.
Error code:
- DK4_E_INVALID_ARGUMENTS
if szptr or mbptr is NULL.
- DK4_E_MATH_OVERFLOW
if a mathematical overflow occured in size calculation.
*/
int
dk4membuf_size(size_t *szptr, dk4_membuf_t *mbptr, dk4_er_t *erp);
#ifdef __cplusplus
}
#endif
/** Default chunk size.
*/
#define DK4MEMBUF_CHUNK_SIZE 4096U
%% module
#include "dk4membuf.h"
#include "dk4mem.h"
#include "dk4maasz.h"
$!trace-include
static
void
dk4membuf_cell_close(dk4_membuf_cell_t *mcptr)
{
if (NULL != mcptr) {
dk4mem_release(mcptr->buf);
mcptr->next = NULL;
mcptr->max = mcptr->used = 0;
dk4mem_free(mcptr);
}
}
static
dk4_membuf_cell_t *
dk4membuf_cell_open(size_t sz, dk4_er_t *erp)
{
dk4_er_t er;
dk4_membuf_cell_t *back = NULL;
size_t nb;
/* Ensure number of bytes is a multiple of the chunk size.
*/
nb = sz / DK4MEMBUF_CHUNK_SIZE;
if (0 != (sz % DK4MEMBUF_CHUNK_SIZE)) { nb++; }
dk4error_init(&er);
nb = dk4ma_size_t_mul(nb, (size_t)(DK4MEMBUF_CHUNK_SIZE), &er);
if (0 != er.ec) { nb = sz; }
/* Allocate
*/
back = dk4mem_new(dk4_membuf_cell_t,1,erp);
if (NULL != back) {
back->next = NULL;
back->max = nb;
back->used = 0;
back->buf = dk4mem_new(char,nb,erp);
if (NULL == back->buf) {
dk4mem_free(back);
back = NULL;
}
}
return back;
}
dk4_membuf_t *
dk4membuf_open(dk4_er_t *erp)
{
dk4_membuf_t *back = NULL;
back = dk4mem_new(dk4_membuf_t,1,erp);
if (NULL != back) {
back->he = 0;
back->last = NULL;
back->first = dk4membuf_cell_open(DK4MEMBUF_CHUNK_SIZE, erp);
if (NULL != back->first) {
back->last = back->first;
} else {
dk4mem_free(back);
back = NULL;
}
}
return back;
}
void
dk4membuf_close(dk4_membuf_t *mbptr)
{
dk4_membuf_cell_t *pc;
dk4_membuf_cell_t *pn;
if (NULL != mbptr) {
pc = mbptr->first;
while (NULL != pc) {
pn = pc->next;
dk4membuf_cell_close(pc);
pc = pn;
}
dk4mem_free(mbptr);
}
}
int
dk4membuf_store(dk4_membuf_t *mbptr, const void *src, size_t sz, dk4_er_t *erp)
{
dk4_membuf_cell_t *pc = NULL;
dk4_membuf_cell_t *pn = NULL;
const char *psrc = NULL;
size_t bl = 0;
int back = 0;
if ((NULL != mbptr) && (NULL != src) && (0 < sz)) {
/* Initialize variables.
*/
back = 1;
pc = mbptr->last;
psrc = (const char *)src;
/* Attempt to fill current cell.
*/
if (pc->max > pc->used) {
bl = pc->max - pc->used;
if (sz < bl) { bl = sz; }
DK4_MEMCPY(&((pc->buf)[pc->used]), psrc, bl);
pc->used += bl;
sz -= bl;
psrc = &(psrc[bl]);
}
/* Use new cell if necessary.
*/
if (0 < sz) {
back = 0;
pn = dk4membuf_cell_open(sz, erp);
if (NULL != pn) {
pc->next = pn;
mbptr->last = pn;
DK4_MEMCPY(pn->buf, psrc, sz);
back = 1;
pn->used = sz;
} else {
mbptr->he = 1;
}
}
} else {
dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
}
return back;
}
int
dk4membuf_size(size_t *szptr, dk4_membuf_t *mbptr, dk4_er_t *erp)
{
dk4_er_t er;
dk4_membuf_cell_t *cp = NULL;
size_t result = (size_t)0U;
int back = 0;
if ((NULL != szptr) && (NULL != mbptr)) {
back = 1;
cp = mbptr->first;
dk4error_init(&er);
while (NULL != cp) {
result = dk4ma_size_t_add(result, cp->used, &er);
cp = cp->next;
}
if (DK4_E_NONE == er.ec) {
back = 1;
*szptr = result;
}
} else {
dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
}
return back;
}