head 1.41;
access;
symbols;
locks; strict;
comment @ * @;
1.41
date 2002.12.17.13.43.19; author mlelstv; state dead;
branches;
next 1.40;
1.40
date 2002.11.29.14.06.52; author mlelstv; state Exp;
branches;
next 1.39;
1.39
date 2002.11.28.17.21.55; author mlelstv; state Exp;
branches;
next 1.38;
1.38
date 2002.11.28.16.11.49; author mlelstv; state Exp;
branches;
next 1.37;
1.37
date 2002.11.28.15.12.40; author mlelstv; state Exp;
branches;
next 1.36;
1.36
date 2002.11.19.17.02.17; author mlelstv; state Exp;
branches;
next 1.35;
1.35
date 2002.11.14.09.22.42; author rse; state Exp;
branches;
next 1.34;
1.34
date 2002.11.05.14.51.37; author mlelstv; state Exp;
branches;
next 1.33;
1.33
date 2002.11.04.13.14.50; author mlelstv; state Exp;
branches;
next 1.32;
1.32
date 2002.10.25.13.29.02; author mlelstv; state Exp;
branches;
next 1.31;
1.31
date 2002.10.23.16.49.29; author mlelstv; state Exp;
branches;
next 1.30;
1.30
date 2002.10.23.13.59.30; author mlelstv; state Exp;
branches;
next 1.29;
1.29
date 2002.10.22.15.33.16; author mlelstv; state Exp;
branches;
next 1.28;
1.28
date 2002.10.22.15.09.44; author mlelstv; state Exp;
branches;
next 1.27;
1.27
date 2002.10.18.14.12.11; author mlelstv; state Exp;
branches;
next 1.26;
1.26
date 2002.10.18.12.41.20; author mlelstv; state Exp;
branches;
next 1.25;
1.25
date 2002.10.18.12.31.50; author mlelstv; state Exp;
branches;
next 1.24;
1.24
date 2002.10.18.12.24.53; author mlelstv; state Exp;
branches;
next 1.23;
1.23
date 2002.10.18.12.08.52; author rse; state Exp;
branches;
next 1.22;
1.22
date 2002.10.18.11.01.59; author rse; state Exp;
branches;
next 1.21;
1.21
date 2002.10.18.10.20.26; author rse; state Exp;
branches;
next 1.20;
1.20
date 2002.10.18.09.09.18; author mlelstv; state Exp;
branches;
next 1.19;
1.19
date 2002.10.18.08.58.19; author mlelstv; state Exp;
branches;
next 1.18;
1.18
date 2002.10.17.15.02.49; author rse; state Exp;
branches;
next 1.17;
1.17
date 2002.10.17.14.16.51; author thl; state Exp;
branches;
next 1.16;
1.16
date 2002.10.17.11.42.43; author thl; state Exp;
branches;
next 1.15;
1.15
date 2002.10.17.10.17.54; author mlelstv; state Exp;
branches;
next 1.14;
1.14
date 2002.10.16.12.37.08; author rse; state Exp;
branches;
next 1.13;
1.13
date 2002.10.16.11.45.30; author mlelstv; state Exp;
branches;
next 1.12;
1.12
date 2002.10.16.09.31.55; author mlelstv; state Exp;
branches;
next 1.11;
1.11
date 2002.10.16.09.28.17; author mlelstv; state Exp;
branches;
next 1.10;
1.10
date 2002.10.16.07.59.00; author mlelstv; state Exp;
branches;
next 1.9;
1.9
date 2002.10.15.13.13.06; author mlelstv; state Exp;
branches;
next 1.8;
1.8
date 2002.10.14.15.44.03; author mlelstv; state Exp;
branches;
next 1.7;
1.7
date 2002.10.14.15.41.37; author mlelstv; state Exp;
branches;
next 1.6;
1.6
date 2002.10.14.15.26.04; author mlelstv; state Exp;
branches;
next 1.5;
1.5
date 2002.10.14.13.45.47; author mlelstv; state Exp;
branches;
next 1.4;
1.4
date 2002.10.14.13.34.25; author mlelstv; state Exp;
branches;
next 1.3;
1.3
date 2002.10.14.12.32.16; author mlelstv; state Exp;
branches;
next 1.2;
1.2
date 2002.10.14.09.17.21; author mlelstv; state Exp;
branches;
next 1.1;
1.1
date 2002.10.14.08.04.46; author mlelstv; state Exp;
branches;
next ;
desc
@@
1.41
log
@moved into its own al project
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@/*
** OSSP al -- Assembly Line
** Copyright (c) 2002 The OSSP Project
** Copyright (c) 2002 Cable & Wireless Deutschland
** Copyright (c) 2002 Ralf S. Engelschall
** Copyright (c) 2002 Michael van Elst
**
** This file is part of OSSP al, an abstract datatype of a data buffer
** that can assemble, move and truncate data but avoids actual copying.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** al.c: assembly line library implementation
*/
#include
#include
#include
#ifdef TEST
#include
#endif
#include "list.h"
#include "al.h"
/* unique library identifier */
const char al_id[] = "OSSP al";
/* support for OSSP ex based exception throwing */
#ifdef WITH_EX
#include "ex.h"
#define AL_RC(rv) \
( (rv) != AL_OK && (ex_catching && !ex_shielding) \
? (ex_throw(al_id, NULL, (rv)), (rv)) : (rv) )
#else
#define AL_RC(rv) (rv)
#endif /* WITH_EX */
struct al_buffer_st;
typedef struct al_buffer_st al_buffer_t;
typedef struct {
void *(*malloc)(size_t); /* malloc(3) style function (for al_chunk_t) */
void (*free)(void *); /* free(3) style function (for al_chunk_t) */
void *(*balloc)(size_t); /* malloc(3) style function (for al_buffer_t) */
void (*bfree)(void *); /* free(3) style function (for al_buffer_t) */
size_t new_buffersize; /* default size for memory underlying al_buffer_t */
int max_freechunks; /* maximum number of cached al_chunk_t objects */
} al_memops_t;
struct al_st {
LIST(al_chunk_t) chunks; /* list header for al_chunk_t objects */
size_t bytes; /* total cached number of bytes in chunk */
al_memops_t m; /* assembly line memory operations (see above) */
};
struct al_chunk_st {
NODE(al_chunk_t) chunks; /* list node for al_chunk_t object chaining */
al_buffer_t *buf; /* (non-exlusively) referenced buffer object */
size_t begin; /* offset into buf->mem where data starts */
size_t end; /* offset into buf->mem where data ends */
al_label_t label; /* tag data with a label, chunks with distinct labels are not coalesced */
};
struct al_buffer_st {
char *mem; /* reference to underlying chunk of data */
size_t size; /* size of underlying chunk of data */
int usecount; /* reference count (from al_chunk_t) */
void (*freemem)(char *p, size_t n, void *u); /* callback function to reclaim memory when it is no longer referenced */
void *userdata; /* arbitrary pointer to pass context data to the callback function */
};
struct al_tx_st {
al_td_t dir; /* traversal direction */
al_chunk_t *cur; /* current chunk during traveral steps */
size_t skip; /* number of bytes to skip for traversal */
size_t togo; /* number of bytes left for traversal */
al_label_t label; /* label filter or NULL */
al_chunk_t view; /* synthetic chunk for returning during traversal steps */
};
/* number of bytes described by a chunk */
#define AL_CHUNK_LEN(alc) \
((alc)->end - (alc)->begin)
/* memory pointer into a chunk, offset must be less than length */
#define AL_CHUNK_PTR(alc, off) \
((alc)->buf->mem + (alc)->begin + (off))
/* number of bytes of a span that are stored in a chunk */
#define AL_CHUNK_SPAN(alc, off, n) \
((n) > (AL_CHUNK_LEN(alc) - (off)) ? \
(AL_CHUNK_LEN(alc) - (off)) : (n))
/* return chunk label */
#define AL_CHUNK_LABEL(alc) \
((alc)->label)
/* check wether labels match */
#define AL_SAME_LABEL(alc,label) \
((label) == NULL || AL_CHUNK_LABEL(alc) == (label))
/*
* number of bytes a chunk can be grown to the end
* we must not grow a chunk in a shared buffer since
* we do not track other chunks sharing the buffer
*/
#define AL_CHUNK_RESERVE(alc,label) \
( (alc) != NULL \
? ( (alc)->buf->usecount > 1 || !AL_SAME_LABEL(alc,label) \
? 0 \
: (alc)->buf->size - (alc)->end) \
: 0)
/* grow chunk to the end */
#define AL_RESIZE(al, alc, n) \
do { (alc)->end += n; (al)->bytes += (n); } while (0)
/*
* number of bytes a chunk can be grown to the beginning
* we must not grow a chunk in a shared buffer since
* we do not track other chunks sharing the buffer
*
* empty chunks can be aligned with end
*/
#define AL_CHUNK_PRESERVE(alc,label) \
( (alc) != NULL \
? ( (alc)->buf->usecount > 1 || !AL_SAME_LABEL(alc,label) \
? 0 \
: (alc)->end <= (alc)->begin ? \
(alc)->buf->size \
: (alc)->begin) \
: 0)
/*
* grow chunk to the beginning
*
* empty chunks can be aligned with end
*/
#define AL_PRESIZE(al, alc, n) \
do { \
if ((alc)->end <= (alc)->begin) \
(alc)->end = (alc)->begin = (alc)->buf->size; \
(alc)->begin -= n; (al)->bytes += (n); \
} while (0)
/*
* callback to release buffer memory allocated by the library
*/
static
void freemem(char *p, size_t n, void *u)
{
void (*f)(void *) = (void (*)(void *))u;
f(p);
}
/*
* allocate backing store and its control structure from heap
*
* can be freed when usecount drops to zero
*/
static al_rc_t
new_buffer(al_t *al, al_buffer_t **bufp)
{
size_t n = al->m.new_buffersize;
al_buffer_t *buf;
if ((buf = (al_buffer_t *)(al->m.malloc)(sizeof(al_buffer_t))) == NULL)
return AL_ERR_MEM;
if ((buf->mem = (al->m.balloc)(n)) == NULL) {
(al->m.free)(buf);
return AL_ERR_MEM;
}
buf->freemem = freemem;
buf->userdata = (void *)al->m.bfree;
buf->size = n;
buf->usecount = 0;
*bufp = buf;
return AL_OK;
}
static al_rc_t
dispose_buffer(al_t *al, al_buffer_t *buf)
{
/* must not happen */
if (buf->usecount != 0)
return AL_ERR_INT;
if (buf->freemem)
(buf->freemem)(buf->mem, buf->size, buf->userdata);
(al->m.free)(buf);
return AL_OK;
}
/*
* allocate only control structure for backing store from heap
* and attach to existing memory
* only the control structure will be freed later
*/
static
al_rc_t make_buffer(al_t *al, char *p, size_t n, void (*freemem_cb)(char *, size_t, void *), void *u, al_buffer_t **bufp)
{
al_buffer_t *buf;
if ((buf = (al_buffer_t *)(al->m.malloc)(sizeof(al_buffer_t))) == NULL)
return AL_ERR_MEM;
buf->mem = p;
buf->freemem = freemem_cb;
buf->userdata = u;
buf->size = n;
buf->usecount = 0;
*bufp = buf;
return AL_OK;
}
/*
* allocate chunks from heap and attach to backing store
* keep some freed chunks in a freelist to avoid expensive malloc()
* and excessive fragmentation
* maintain usage count of backing store
* free backing store when no longer in use, this also includes
* the case where new_chunk fails and the buffer has no other
* users
*/
static struct {
LIST(al_chunk_t) chunks;
} alc_freelist;
static int alc_freecount = 0;
static al_rc_t
new_chunk(al_t *al, al_buffer_t *buf, al_label_t label, al_chunk_t **alcp)
{
al_chunk_t *alc;
if (ISEMPTY(&alc_freelist, chunks)) {
if ((alc = (al_chunk_t *)(al->m.malloc)(sizeof(al_chunk_t))) == NULL) {
if (buf->usecount == 0)
dispose_buffer(al,buf);
return AL_ERR_MEM;
}
} else {
/* thl: FIXME i would suggest using REMTAIL() here because dispose_chunk
* puts the latest disposed chunks at the end of the list and
* those latest data should have a closer approximation to the
* CPU in terms of internal cache, external cache, RAM and VM
*/
REMHEAD(&alc_freelist, chunks, alc);
--alc_freecount;
}
NODEINIT(alc, chunks);
alc->buf = buf;
alc->begin = 0;
alc->end = 0;
alc->label = label;
buf->usecount++;
*alcp = alc;
return AL_OK;
}
static al_rc_t
split_chunk(al_t *al, al_chunk_t *orig, size_t off, al_chunk_t **alcp)
{
al_rc_t rc;
al_chunk_t *alc;
size_t len = AL_CHUNK_LEN(orig);
if (off > len)
return AL_ERR_ARG;
rc = new_chunk(al, orig->buf, orig->label, &alc);
if (rc != AL_OK)
return rc;
alc->begin = orig->begin;
alc->end = orig->begin+off;
orig->begin = alc->end;
*alcp = alc;
return AL_OK;
}
static void
dispose_chunk(al_t *al, al_chunk_t *alc)
{
alc->buf->usecount--;
if (alc->buf->usecount == 0)
dispose_buffer(al,alc->buf);
alc->buf = NULL;
alc->label = NULL;
/* stop freelist from growing infinitely */
if (alc_freecount >= al->m.max_freechunks)
(al->m.free)(alc);
else {
ADDTAIL(&alc_freelist, chunks, alc);
alc_freecount++;
}
}
/*
* find chunk that represents a particular offset
* a reference to the chunk is stored in *alcp
* the relative offset into the chunk is stored in *skipp
* return AL_OK and *alcp == NULL if positioned exactly to end of list
* return AL_ERR_EOF when no such chunk can be found
*/
static al_rc_t
al_seek(al_t *al, size_t off, al_chunk_t **alcp, size_t *skipp)
{
al_chunk_t *cur;
size_t pos, end;
size_t chunksize;
if ((al->bytes / 2) >= off) { /* FIXME poor man's heuristic */
/* forward search */
pos = 0;
FOREACH(al,chunks,cur) {
chunksize = AL_CHUNK_LEN(cur);
end = pos+chunksize;
if (pos <= off && off < end) {
*alcp = cur;
*skipp = off - pos;
return AL_OK;
}
if (end > off)
break;
pos = end;
}
/* seek to EOF position is ok */
if (pos == off) {
*alcp = NULL;
*skipp = 0;
return AL_OK;
}
} else {
/* reverse search */
pos = al->bytes;
/* seek to EOF position is ok */
if (pos == off) {
*alcp = NULL;
*skipp = 0;
return AL_OK;
}
FOREACHR(al,chunks,cur) {
chunksize = AL_CHUNK_LEN(cur);
end = pos;
pos -= chunksize;
if (pos <= off && off < end) {
*alcp = cur;
*skipp = off - pos;
return AL_OK;
}
if (pos < off)
break;
}
}
return AL_ERR_EOF;
}
#ifdef TEST
static void
dump(al_t *al)
{
al_chunk_t *cur;
size_t total;
printf("AL: %p\n", al);
total = 0;
FOREACH(al,chunks,cur) {
printf(" C: %p [%p] (%d @@ %p + %d < %d (use=%d))\n",
cur,
cur->label,
cur->buf->size,cur->buf->mem,
cur->begin,cur->end,
cur->buf->usecount);
total += AL_CHUNK_LEN(cur);
}
printf("size = %d == %d\n",al->bytes,total);
printf("--\n\n");
}
#endif
/****************************************************************************/
/*
* allocate an empty assembly line
* dispose all chunks and all allocated backing store
*/
al_rc_t
al_create(al_t **alp)
{
al_t *al;
/* argument sanity check(s) */
if (alp == NULL)
return AL_RC(AL_ERR_ARG);
/* allocate and initialize new assembly line object */
/* XXX - what malloc ? */
if ((al = (al_t *)malloc(sizeof(al_t))) == NULL)
return AL_RC(AL_ERR_MEM);
LISTINIT(al,chunks);
al->bytes = 0;
/* memory policy */
al->m.malloc = malloc; /* structure allocation */
al->m.free = free;
al->m.balloc = malloc; /* buffer allocation */
al->m.bfree = free;
#ifdef TEST
al->m.new_buffersize = 42;
#else
al->m.new_buffersize = 4096;
#endif
al->m.max_freechunks = 500;
/* pass object to caller */
*alp = al;
return AL_OK;
}
al_rc_t
al_destroy(al_t *al)
{
al_chunk_t *cur, *pred;
/* argument sanity check(s) */
if (al == NULL)
return AL_RC(AL_ERR_ARG);
/* free chunks and backing store */
FOREACHD(al,chunks,cur,pred) {
REMOVE(al,chunks,cur);
dispose_chunk(al,cur);
}
/* free object itself */
/* XXX - which free() ? */
free(al);
return AL_OK;
}
/*
* copy bytes into buffer, FIFO
*
* stops copy operation when a new buffer cannot be created
* but leaves data structure consistent
*/
al_rc_t
al_append_bytes(al_t *al, const char *src, size_t n, al_label_t label)
{
al_rc_t rc;
al_chunk_t *cur;
al_buffer_t *buf;
size_t res, step;
char *dst;
/* argument sanity check(s) */
if (al == NULL || src == NULL)
return AL_RC(AL_ERR_ARG);
cur = TAIL(al,chunks);
res = AL_CHUNK_RESERVE(cur,label);
while (n > 0) {
if (res == 0) {
rc = new_buffer(al, &buf);
if (rc != AL_OK)
return AL_RC(rc);
rc = new_chunk(al,buf,label,&cur);
if (rc != AL_OK)
return AL_RC(rc);
res = AL_CHUNK_RESERVE(cur,label);
ADDTAIL(al, chunks, cur);
}
step = n;
if (step > res)
step = res;
dst = AL_CHUNK_PTR(cur, AL_CHUNK_LEN(cur));
memcpy(dst, src, step);
src += step;
AL_RESIZE(al, cur, step);
n -= step;
res = AL_CHUNK_RESERVE(cur,label);
}
return AL_OK;
}
/*
* copy bytes into buffer, LIFO
*
* stops copy operation when a new buffer cannot be created
* but leaves data structure consistent
*/
al_rc_t
al_prepend_bytes(al_t *al, const char *src, size_t n, al_label_t label)
{
al_rc_t rc;
al_chunk_t *cur;
al_buffer_t *buf;
size_t res, step;
char *dst;
/* argument sanity check(s) */
if (al == NULL || src == NULL)
return AL_RC(AL_ERR_ARG);
cur = HEAD(al,chunks);
res = AL_CHUNK_PRESERVE(cur,label);
src += n;
while (n > 0) {
if (res == 0) {
rc = new_buffer(al, &buf);
if (rc != AL_OK)
return AL_RC(rc);
rc = new_chunk(al,buf,label,&cur);
if (rc != AL_OK)
return AL_RC(rc);
res = AL_CHUNK_PRESERVE(cur,label);
ADDHEAD(al, chunks, cur);
}
step = n;
if (step > res)
step = res;
src -= step;
AL_PRESIZE(al, cur, step);
n -= step;
res = AL_CHUNK_PRESERVE(cur,label);
dst = AL_CHUNK_PTR(cur, 0);
memcpy(dst, src, step);
}
return AL_OK;
}
/*
* append a caller supplied buffer
*
* buffer must exist until list is destroyed
* XXX - buffer can have multiple refs caused by splice operations
* XXX - some list operations modify the buffer
*
*/
al_rc_t al_attach_buffer(al_t *al, char *p, size_t n, al_label_t label,
void (*freemem_cb)(char *, size_t, void *), void *u)
{
al_rc_t rc;
al_buffer_t *buf;
al_chunk_t *cur;
/* argument sanity check(s) */
if (al == NULL || p == NULL || n <= 0)
return AL_RC(AL_ERR_ARG);
rc = make_buffer(al, p, n, freemem_cb, u, &buf);
if (rc != AL_OK)
return AL_RC(rc);
rc = new_chunk(al,buf,label,&cur);
if (rc != AL_OK)
return AL_RC(rc);
ADDTAIL(al, chunks, cur);
/* validate data in buffer */
AL_RESIZE(al, cur, n);
return AL_OK;
}
/*
* this is the central function to manipulate assembly line
*
* cut arbitrary spans from list into a destination buffer (or drop it)
* insert (destructive move) content from another list into the cut
*
* this is analog to perls splice function, except that
* -> the output is not stored in the target buffer but is appended
* -> the replacement data is moved and not copied.
*
*/
al_rc_t
al_splice(al_t *al, size_t off, size_t n, al_t *nal, al_t *tal)
{
al_rc_t rc;
al_chunk_t *cur, *start, *end, *next, *ins, *splitbuf;
size_t pos, skip, len, step;
int doinsert;
/* argument sanity check(s) */
if (al == NULL)
return AL_RC(AL_ERR_ARG);
/* optimization: treat an empty list as no insertion at all */
doinsert = (nal != NULL) && !ISEMPTY(nal,chunks);
/*
* seek to beginning, return EOF when seek position does not exist
* EOD must be a valid seek position so that we can append data
*/
rc = al_seek(al, off, &cur, &skip);
if (rc != AL_OK)
return AL_RC(rc);
/*
* remember insertion point
*
* caveat: if the first chunk is removed from input the insertion
* point shifts to the next chunk (or EOD -> NULL pointer)
*/
ins = cur;
/*
* the inseration point is either behind the list or
* within the current chunk
*
* if it is behind the list:
* -> insert operation switches to append mode
*
* if the insertion point is at the beginning of the current chunk:
* -> insertion point moves later if the chunk is removed
*
* if the inseration point is in the middle of the current chunk:
* -> chunk is split into two so that the insertion
* point is at the beginning of the second part
*
* insertion point cannot be at EOD of the chunk
*
* splitting at this point preserves all data in case the
* allocation of the split buffer fails
*/
if (doinsert) {
if (ins != NULL && skip > 0) {
rc = split_chunk(al, ins, skip, &splitbuf);
if (rc != AL_OK)
return AL_RC(rc);
INSERT(al,chunks,ins,splitbuf);
skip = 0;
}
}
/*
* as long as there is data to move
*/
pos = off;
while (n > 0 && cur != NULL) {
next = NEXT(cur, chunks);
len = AL_CHUNK_LEN(cur);
/*
* check if partial chunk was selected
* if skip > 0 we have to preserve bytes at the beginning
* if skip == 0 && n < len-skip we have to preserve bytes at the end
*/
if (skip > 0 || n < len - skip) {
/* compute number of bytes to process */
step = AL_CHUNK_SPAN(cur, skip, n);
/* copy data to target */
if (tal != NULL) {
/*
* XXX - this operation can fail
*/
size_t before = tal->bytes;
rc = al_append_bytes(tal, AL_CHUNK_PTR(cur, skip),
step, AL_CHUNK_LABEL(cur));
if (rc != AL_OK)
/* correct step size to actual size */
step = tal->bytes - before;
} else
rc = AL_OK;
/*
* cut span from src chunk
* if skip == 0, simply shrink the chunk from the beginning
* if skip > 0, compute number of bytes to preserve,
* align buffer and shrink chunk from the end
*/
if (skip == 0)
AL_PRESIZE(al, cur, -step);
else {
/* align trailing bytes */
if (len > (skip+step)) {
memmove(
AL_CHUNK_PTR(cur, skip),
AL_CHUNK_PTR(cur, skip+step),
len - (skip+step)
);
}
AL_RESIZE(al, cur, -step);
}
/*
* bail out from failed al_append_bytes operation above
*
*/
if (rc != AL_OK)
return AL_RC(rc);
}
else {
/*
* the whole chunk has to be moved,
*
* scan ahead for more such chunks to unlink
* and relink a whole chain in a single operation
*
* move the chunks to the target chain
* manual accounting for total size
*/
/*
* when the insertion chunk is removed, we have to adjust
* the insertion point
*
* if the insertion chunk was the last chunk we get a NULL
* next pointer and the insertion method switches to append
* mode
*/
step = len;
start = cur;
end = cur;
if (cur == ins)
ins = next;
while (next && step + (len = AL_CHUNK_LEN(next)) <= n) {
step += len;
end = next;
next = NEXT(next, chunks);
if (end == ins)
ins = next;
}
REMOVE2(al, chunks, start, end);
al->bytes -= step;
if (tal == NULL) {
do {
cur = start;
start = NEXT(cur, chunks);
dispose_chunk(al, cur);
} while (cur != end);
} else {
ADDTAIL2(tal, chunks, start, end);
tal->bytes += step;
}
}
n -= step;
pos += step;
cur = next;
skip = 0;
}
/*
* now splice in replacement chunks
*/
if (doinsert) {
if (ins != NULL) {
/*
* complex case where list is inserted
*
* the original list has already been modified so
* that we can simply insert between two chunks
*/
INSERTLIST(al,chunks,ins,nal);
} else {
/*
* simple case where list end is 'replaced'
*/
APPENDLIST(al,chunks,nal);
}
al->bytes += nal->bytes;
nal->bytes = 0;
}
return AL_OK;
}
/*
*
*/
al_rc_t
al_setlabel(al_t *al, size_t off, size_t n,
al_label_t oldlabel, al_label_t newlabel)
{
al_rc_t rc;
al_chunk_t *cur, *splitbuf;
size_t skip, len;
/* argument sanity check(s) */
if (al == NULL)
return AL_RC(AL_ERR_ARG);
/*
* seek to beginning, return EOF when seek position does not exist
* EOD must be a valid seek position so that we can append data
*/
rc = al_seek(al, off, &cur, &skip);
if (rc != AL_OK)
return AL_RC(rc);
/*
* seek to EOD, nothing to label
*/
if (cur == NULL)
return AL_OK;
/*
* if first chunk doesn't need relabeling
* then skip it, adjust seek size
*
* else if offset is not at chunk start
* then split chunk at offset, continue
* with second half
*/
if (!AL_SAME_LABEL(cur, oldlabel) ||
AL_SAME_LABEL(cur, newlabel)) {
len = AL_CHUNK_LEN(cur) - skip;
n = n < len ? 0 : n - len;
cur = NEXT(cur, chunks);
} else if (skip > 0) {
rc = split_chunk(al, cur, skip, &splitbuf);
if (rc != AL_OK)
return AL_RC(rc);
INSERT(al,chunks,cur,splitbuf);
}
/*
* for all remaining chunks and bytes
*
* if chunk doesn't need relabeling
* then skip it, adjust size
*
* else if chunk isn't covered in total
* then split chunk at end offset and
* process first half
*/
while (n > 0 && cur != NULL) {
len = AL_CHUNK_LEN(cur);
if (!AL_SAME_LABEL(cur, oldlabel) ||
AL_SAME_LABEL(cur, newlabel)) {
n = n < len ? 0 : n - len;
} else {
if (n < len) {
/*
* split last chunk at end offset
*/
rc = split_chunk(al, cur, n, &splitbuf);
if (rc != AL_OK)
return AL_RC(rc);
INSERT(al,chunks,cur,splitbuf);
cur = splitbuf;
len = AL_CHUNK_LEN(cur);
}
AL_CHUNK_LABEL(cur) = newlabel;
n -= len;
}
cur = NEXT(cur, chunks);
}
return AL_OK;
}
/*
* assembly line traversal requires a context. It needs to be
* malloced to keep its inner structure private
*/
al_rc_t
al_txalloc(al_t *al, al_tx_t **txp)
{
al_tx_t *tx;
tx = (al_tx_t*)(al->m.malloc)(sizeof(al_tx_t));
if (tx == NULL)
return AL_RC(AL_ERR_MEM);
*txp = tx;
return AL_OK;
}
/*
* free traversal context using proper policy function
*/
al_rc_t
al_txfree(al_t *al, al_tx_t *tx)
{
(al->m.free)(tx);
return AL_OK;
}
/*
* initiate assembly line traversal
*
* - do initial seek, fail if position does not exist
* - save traversal parameters
*/
al_rc_t
al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label, al_tx_t *tx)
{
al_rc_t rc;
tx->cur = NULL;
rc = al_seek(al, off, &tx->cur, &tx->skip);
if (rc != AL_OK)
return AL_RC(rc);
tx->dir = dir;
tx->togo = n;
tx->label = label;
return AL_OK;
}
/*
* assembly line traversal step
*
* return EOF if at end of assembly line
* clip view chunk to traversal bounds
* advance chunk cursor according to traversal direction
*/
al_rc_t
al_traverse_next(al_t *al, al_tx_t *tx, al_chunk_t **alcp)
{
size_t step;
do {
if (tx->togo <= 0) /* XXX - togo can be negative from bad input */
return AL_ERR_EOF;
if (tx->cur == NULL) /* premature EOF */
return AL_ERR_EOF;
/* compute number of bytes to process */
step = AL_CHUNK_SPAN(tx->cur, tx->skip, tx->togo);
/*
* synthetic chunk which is NOT maintained in usecount
* MUST NOT BE USED for modifications to chunk list
* MUST NOT BE USED for modifications to chunk size
* ALLOWED is read access to chunk content
* ALLOWED is modification in place of chunk content
*/
tx->view = *(tx->cur);
tx->view.begin += tx->skip;
tx->view.end = tx->view.begin + step;
switch (tx->dir) {
case AL_FORWARD:
case AL_BACKWARD:
break;
case AL_FORWARD_SPAN:
case AL_BACKWARD_SPAN:
if (!AL_SAME_LABEL(&tx->view, tx->label)) {
tx->togo = 0;
return AL_ERR_EOF;
}
break;
}
switch (tx->dir) {
case AL_FORWARD:
case AL_FORWARD_SPAN:
tx->cur = NEXT(tx->cur,chunks);
tx->togo -= step;
tx->skip = 0;
break;
case AL_BACKWARD:
case AL_BACKWARD_SPAN:
tx->cur = PREV(tx->cur,chunks);
tx->togo -= step;
tx->skip = 0;
break;
}
} while (!AL_SAME_LABEL(&tx->view, tx->label));
*alcp = &tx->view;
return AL_OK;
}
/*
* assembly line traversal end
*
* to free resources allocated/locked during traversal
* currently a NOOP
*/
al_rc_t al_traverse_end(al_t *al, al_tx_t *tx, int final)
{
return AL_OK;
}
/*
* full assembly line traversal with callback
*
* traversal is aborted when callback return != AL_OK
* reaching EOF (and also aborting with AL_ERR_EOF) is not an error
*
* traversal context is kept on stack (XXX ?)
*/
al_rc_t
al_traverse_cb(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label,
al_rc_t (*cb)(al_chunk_t *, void *), void *u)
{
al_rc_t rc;
al_tx_t tx; /* XXX - private tx structure on stack */
al_chunk_t *view;
rc = al_traverse(al, off, n, dir, label, &tx);
if (rc != AL_OK)
return AL_RC(rc);
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
rc = cb(view, u);
if (rc != AL_OK)
break;
}
al_traverse_end(al, &tx, 1);
if (rc != AL_ERR_EOF)
return AL_RC(rc);
return AL_OK;
}
/*
* full assembly line traversal with data copy to linear buffer
*
* returns actual number of bytes copied
*
* Do not copy if destination pointer is NULL, but still count.
* This can be used to precalculate the size of the needed linear
* buffer with n set to some arbitrary huge value.
*
* traversal context is kept on stack (XXX ?)
*/
al_rc_t
al_flatten(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label,
char *dst, size_t *lenp)
{
al_rc_t rc;
al_tx_t tx; /* XXX - private tx structure on stack */
al_chunk_t *view;
size_t step, total;
*lenp = 0; /* keep caller on safe side */
rc = al_traverse(al, off, n, dir, label, &tx);
if (rc != AL_OK)
return AL_RC(rc);
switch (dir) {
case AL_FORWARD:
case AL_FORWARD_SPAN:
break;
case AL_BACKWARD:
case AL_BACKWARD_SPAN:
dst += n;
break;
}
total = 0;
if (dst == NULL) {
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK)
total += AL_CHUNK_LEN(view);
} else {
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
step = AL_CHUNK_LEN(view);
switch (dir) {
case AL_FORWARD:
case AL_FORWARD_SPAN:
memmove(dst, AL_CHUNK_PTR(view, 0), step);
dst += step;
break;
case AL_BACKWARD:
case AL_BACKWARD_SPAN:
dst -= step;
memmove(dst, AL_CHUNK_PTR(view, 0), step);
break;
}
total += step;
}
}
*lenp = total;
al_traverse_end(al, &tx, 1);
if (rc != AL_ERR_EOF)
return AL_RC(rc);
return AL_OK;
}
/*
* full assembly line traversal with data copy to target assembly line
*
* traversal context is kept on stack (XXX ?)
*/
al_rc_t
al_copy(al_t *al, size_t off, size_t n, al_label_t label, al_t *tal)
{
al_rc_t rc;
al_tx_t tx; /* XXX - private tx structure on stack */
al_chunk_t *view;
size_t step;
rc = al_traverse(al, off, n, AL_FORWARD, label, &tx);
if (rc != AL_OK)
return AL_RC(rc);
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
step = AL_CHUNK_LEN(view);
al_append_bytes(tal, AL_CHUNK_PTR(view, 0), step, AL_CHUNK_LABEL(view));
}
al_traverse_end(al, &tx, 1);
if (rc != AL_ERR_EOF)
return AL_RC(rc);
return AL_OK;
}
/*
* traverse assembly line and retrieve first chunk
*
* traversal context is kept on stack (XXX ?)
*/
al_rc_t
al_firstlabel(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label,
al_label_t *labelp)
{
al_rc_t rc;
al_tx_t tx; /* XXX - private tx structure on stack */
al_chunk_t *view;
rc = al_traverse(al, off, n, dir, label, &tx);
if (rc != AL_OK)
return AL_RC(rc);
if ((rc = al_traverse_next(al, &tx, &view)) == AL_OK)
*labelp = AL_CHUNK_LABEL(view);
al_traverse_end(al, &tx, 1);
return rc;
}
/*
* traverse assembly line forward and search first chunk
* that matches label and continue search until end of
* span of same label
*
* return offset to first byte in *offp
* return size of span to last byte in *spanp
*
* traversal context is kept on stack (XXX ?)
*/
al_rc_t
al_spanlabel(al_t *al, size_t off, size_t n, al_label_t label,
size_t *offp, size_t *spanp)
{
al_rc_t rc;
al_tx_t tx; /* XXX - private tx structure on stack */
al_chunk_t *view;
size_t len, total, start;
int have_first;
/*
* we need to track absolute traversal position,
* so we have to see all chunks.. no filtering
* allowed
*/
rc = al_traverse(al, off, n, AL_FORWARD, NULL, &tx);
if (rc != AL_OK)
return AL_RC(rc);
have_first = 0;
start = 0;
total = 0;
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
len = AL_CHUNK_LEN(view);
if (AL_SAME_LABEL(view, label)) {
if (!have_first) {
start = total;
have_first = 1;
}
} else if (have_first)
break;
total += len;
}
al_traverse_end(al, &tx, 1);
if (rc != AL_OK && rc != AL_ERR_EOF)
return AL_RC(rc);
if (!have_first)
return AL_RC(AL_ERR_EOF);
*offp = off + start;
*spanp = total - start;
return AL_OK;
}
/*
* relay macros to caller
*
* al_bytes - total number of bytes in assembly line
* al_chunk_len - number of bytes in chunk
* al_chunk_span - clip interval (off,off+n( against chunk length
* al_chunk_label- return chunk label
* al_same_label - check if label matches with chunk label
* al_chunk_ptr - return memory pointer to byte within chunk
*
* off must be a valid offset within (0,len(
*/
size_t
al_bytes(const al_t *al)
{
return al->bytes;
}
size_t
al_chunk_len(al_chunk_t *alc)
{
return AL_CHUNK_LEN(alc);
}
size_t
al_chunk_span(al_chunk_t *alc, size_t off, size_t n)
{
return AL_CHUNK_SPAN(alc, off, n);
}
al_label_t
al_chunk_label(al_chunk_t *alc)
{
return AL_CHUNK_LABEL(alc);
}
int
al_same_label(al_chunk_t *alc, al_label_t label)
{
return AL_SAME_LABEL(alc, label);
}
char *
al_chunk_ptr(al_chunk_t *alc, size_t off)
{
return AL_CHUNK_PTR(alc, off);
}
/*
* convert error code into human readable form
*/
const char *
al_error(al_rc_t rc)
{
const char *mess;
switch (rc) {
case AL_OK: mess = "Everything Ok"; break;
case AL_ERR_ARG: mess = "Invalid Argument"; break;
case AL_ERR_MEM: mess = "Not Enough Memory"; break;
case AL_ERR_EOF: mess = "End Of Data"; break;
case AL_ERR_INT: mess = "Internal Error"; break;
default: mess = "Invalid Result Code"; break;
}
return mess;
}
@
1.40
log
@get rid of superflous unsigned<0 tests
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@@
1.39
log
@make al_setlabel conditional (use oldlabel == NULL for unconditional
behavíour)
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d490 1
a490 1
if (al == NULL || src == NULL || n < 0)
d539 1
a539 1
if (al == NULL || src == NULL || n < 0)
d627 1
a627 1
if (al == NULL || n < 0)
d832 1
a832 1
if (al == NULL || n < 0)
@
1.38
log
@new al_spanlabel method
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d824 2
a825 1
al_setlabel(al_t *al, size_t off, size_t n, al_label_t label)
d857 2
a858 1
if (AL_SAME_LABEL(cur, label)) {
d881 2
a882 1
if (AL_SAME_LABEL(cur, label)) {
d896 1
a896 1
AL_CHUNK_LABEL(cur) = label;
@
1.37
log
@new al_setlabel method to modify the data label within an
assembly line.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d1189 58
@
1.36
log
@buffers can move to different assembly lines so that the freemem
function can reference a dangling al pointer to reach bfree().
We now reference the bfree() function directly as this is supposed
to remain valid even after an assembly line has been freed.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d821 82
@
1.35
log
@remove remaining GCC warnings
@
text
@d170 2
a171 2
al_t *al = (al_t *)u;
(al->m.bfree)(p);
d194 1
a194 1
buf->userdata = (void *)al;
@
1.34
log
@size_t is unsigned -> get rid of possible negative offsets that weren't used
anywhere. remove sanity checks for 'unsigned < 0'.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d222 1
a222 1
al_rc_t make_buffer(al_t *al, char *p, size_t n, void (*freemem)(char *, size_t, void *), void *u, al_buffer_t **bufp)
d231 1
a231 1
buf->freemem = freemem;
d583 1
a583 1
void (*freemem)(char *, size_t, void *), void *u)
d593 1
a593 1
rc = make_buffer(al, p, n, freemem, u, &buf);
@
1.33
log
@prepending to a zero length chunk is now possible, the chunk
is aligned to the end of the buffer
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d294 1
a294 1
if (off < 0 || off > len)
a328 1
* if off is negative, treat it as relative offset from the end
a339 3
if (off < 0) /* off is negative */
off += al->bytes;
@
1.32
log
@optimize al_splice to unlink/relink several chunks in a single step
added necessary list macros to list.h
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d140 2
d147 3
a149 1
: (alc)->begin) \
d152 5
a156 1
/* grow chunk to the beginning */
d158 5
a162 1
do { (alc)->begin -= n; (al)->bytes += (n); } while (0)
@
1.31
log
@new span traversal mode
add direction to al_flatten to support span traversal
utility method al_firstlabel
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d614 1
a614 1
al_chunk_t *cur, *next, *ins, *splitbuf;
d733 6
a738 2
* the whole chunk has to be moved, simply move it
* to the target chain
a740 2
step = len;
REMOVE(al, chunks, cur);
d750 5
d758 9
d768 8
a775 4
if (tal == NULL)
dispose_chunk(al, cur);
else {
ADDTAIL(tal, chunks, cur);
@
1.30
log
@seeking backwards to EOF position is obviously ok as well
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d582 1
a582 1
if (al == NULL || p == NULL || n < 0)
d877 13
d891 1
d897 1
d966 1
a966 1
al_flatten(al_t *al, size_t off, size_t n, al_label_t label,
d976 1
a976 1
rc = al_traverse(al, off, n, AL_FORWARD, label, &tx);
d980 10
a990 2
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
step = AL_CHUNK_LEN(view);
d992 19
a1010 3
if (dst != NULL) {
memmove(dst, AL_CHUNK_PTR(view, 0), step);
dst += step;
a1011 2
total += step;
d1051 25
@
1.29
log
@significant API change.
now support data labels.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d357 6
@
1.28
log
@prepend used wrong macros (cut&paste error)
traverse_next didn't compute step correctly and didn't clear skip
from initial seek when moving to next/previous chunk
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d79 1
d95 1
d112 8
d125 1
a125 1
#define AL_CHUNK_RESERVE(alc) \
d127 1
a127 1
? ( (alc)->buf->usecount > 1 \
d141 1
a141 1
#define AL_CHUNK_PRESERVE(alc) \
d143 1
a143 1
? ( (alc)->buf->usecount > 1 \
d243 1
a243 1
new_chunk(al_t *al, al_buffer_t *buf, al_chunk_t **alcp)
d267 1
d285 1
a285 1
rc = new_chunk(al, orig->buf, &alc);
d304 1
d384 1
a384 1
printf(" C: %p (%d @@ %p + %d < %d (use=%d))\n",
d386 1
d467 1
a467 1
al_append_bytes(al_t *al, const char *src, size_t n)
d480 1
a480 1
res = AL_CHUNK_RESERVE(cur);
d487 1
a487 1
rc = new_chunk(al,buf,&cur);
d490 1
a490 1
res = AL_CHUNK_RESERVE(cur);
d503 1
a503 1
res = AL_CHUNK_RESERVE(cur);
d516 1
a516 1
al_prepend_bytes(al_t *al, const char *src, size_t n)
d529 1
a529 1
res = AL_CHUNK_PRESERVE(cur);
d538 1
a538 1
rc = new_chunk(al,buf,&cur);
d541 1
a541 1
res = AL_CHUNK_PRESERVE(cur);
d551 1
a551 1
res = AL_CHUNK_PRESERVE(cur);
d568 2
a569 1
al_rc_t al_attach_buffer(al_t *al, char *p, size_t n, void (*freemem)(char *, size_t, void *), void *u)
d582 1
a582 1
rc = new_chunk(al,buf, &cur);
d689 2
a690 1
rc = al_append_bytes(tal, AL_CHUNK_PTR(cur, skip), step);
d820 1
a820 1
al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_tx_t *tx)
d830 3
a832 2
tx->dir = dir;
tx->togo = n;
d849 3
a851 2
if (tx->togo <= 0) /* XXX - togo can be negative from bad input */
return AL_ERR_EOF;
d853 2
a854 2
if (tx->cur == NULL) /* premature EOF */
return AL_ERR_EOF;
d856 2
a857 2
/* compute number of bytes to process */
step = AL_CHUNK_SPAN(tx->cur, tx->skip, tx->togo);
d859 24
a882 23
/*
* synthetic chunk which is NOT maintained in usecount
* MUST NOT BE USED for modifications to chunk list
* MUST NOT BE USED for modifications to chunk size
* ALLOWED is read access to chunk content
* ALLOWED is modification in place of chunk content
*/
tx->view = *(tx->cur);
tx->view.begin += tx->skip;
tx->view.end = tx->view.begin + step;
switch (tx->dir) {
case AL_FORWARD:
tx->cur = NEXT(tx->cur,chunks);
tx->togo -= step;
tx->skip = 0;
break;
case AL_BACKWARD:
tx->cur = PREV(tx->cur,chunks);
tx->togo -= step;
tx->skip = 0;
break;
}
d908 1
a908 1
al_traverse_cb(al_t *al, size_t off, size_t n, al_td_t dir,
d915 1
a915 1
rc = al_traverse(al, off, n, dir, &tx);
d938 4
d945 2
a946 1
al_flatten(al_t *al, size_t off, size_t n, char *dst, size_t *lenp)
d955 1
a955 1
rc = al_traverse(al, off, n, AL_FORWARD, &tx);
d962 6
a967 2
memmove(dst, AL_CHUNK_PTR(view, 0), step);
dst += step;
d986 1
a986 1
al_copy(al_t *al, size_t off, size_t n, al_t *tal)
d993 1
a993 1
rc = al_traverse(al, off, n, AL_FORWARD, &tx);
d999 1
a999 1
al_append_bytes(tal, AL_CHUNK_PTR(view, 0), step);
d1016 2
d1039 12
@
1.27
log
@beautification
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d536 1
a536 1
AL_RESIZE(al, cur, step);
d538 1
a538 1
res = AL_CHUNK_RESERVE(cur);
d839 2
a840 3
step = AL_CHUNK_LEN(tx->cur);
if (step > tx->togo)
step = tx->togo;
d857 1
d862 1
@
1.26
log
@correctly initialize callback userdata
get rid of debug printf
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d85 2
a86 2
void (*freemem)(char *p, size_t n, void *u); /* callback function to reclaim memory when it is no longer referenced */
void *userdata; /* arbitrary pointer to pass context data to the callback function */
@
1.25
log
@after splitting initial chunk, the split offset ("skip") needs
to be reset to zero.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@a147 1
printf("*** FREEMEM(LIBRARY) buffer %p size %d\n",p,n);
d172 1
a172 1
buf->userdata = NULL;
@
1.24
log
@change in al_attach_buffer API
back out rse's change to al_traverse parameters.
parameter order is: object ptr(if any), input parameters, output parameters
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d647 1
@
1.23
log
@Undocumented internal code is usually always ok (at least as long as it
is self-describing enough ;-), but undocumented internal data is most of
the time nasty. It especially makes it hard to review anything in-depth
because only the author has all of the gory details in mind all the
time. Hence internal data should be documented at least a little bit to
make clear for what each structure member is for. So, here it is. Feel
free to fix my quick descriptions.
@
text
@d85 2
a86 1
int freemem; /* boolean flag whether chunk of data has to be free(3)ed */
d143 11
d172 2
a173 1
buf->freemem = 1;
d189 1
a189 1
(al->m.bfree)(buf->mem);
d200 2
a201 2
static al_rc_t
make_buffer(al_t *al, char *p, size_t n, al_buffer_t **bufp)
d210 2
a211 1
buf->freemem = 0;
d556 1
a556 2
al_rc_t
al_attach_buffer(al_t *al, char *p, size_t n)
d566 1
a566 1
rc = make_buffer(al, p, n, &buf);
d805 1
a805 1
al_traverse(al_t *al, al_tx_t *tx, size_t off, size_t n, al_td_t dir)
d896 1
a896 1
rc = al_traverse(al, &tx, off, n, dir);
d931 1
a931 1
rc = al_traverse(al, &tx, off, n, AL_FORWARD);
d965 1
a965 1
rc = al_traverse(al, &tx, off, n, AL_FORWARD);
@
1.22
log
@Be pedantic about consistent argument orders and move al_tx_t argument
to second position where it is for all other al_tx_t based functions:
-al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_tx_t *tx)
+al_traverse(al_t *al, al_tx_t *tx, size_t off, size_t n, al_td_t dir)
@
text
@d60 6
a65 6
void *(*malloc)(size_t);
void (*free)(void *);
void *(*balloc)(size_t);
void (*bfree)(void *);
size_t new_buffersize;
int max_freechunks;
d69 3
a71 3
LIST(al_chunk_t) chunks;
size_t bytes;
al_memops_t m;
d75 4
a78 3
NODE(al_chunk_t) chunks;
al_buffer_t *buf;
size_t begin, end;
d82 4
a85 4
char *mem;
size_t size;
int usecount;
int freemem;
d89 5
a93 5
al_td_t dir;
al_chunk_t *cur;
size_t skip;
size_t togo;
al_chunk_t view;
@
1.21
log
@Before diving into the semantics, bring syntax into standard
OSSP shape by applying the following cosmetics:
- add newlines between "if" and "return" at some statements
- make sure indentation is exactly 4 spaces (were 8 at dispose_chunk, etc)
- consistently use no braces for "if" or "else" clauses if only single
statement exists in body.
- we do not indicate the not-used-return-code via (void) on statements,
because both every compiler and human is smart enough to see the
intention.
THERE ARE NO FUNCTIONAL CHANGES IN THIS COMMIT AT ALL.
@
text
@d791 1
a791 1
al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_tx_t *tx)
d882 1
a882 1
rc = al_traverse(al, off, n, dir, &tx);
d917 1
a917 1
rc = al_traverse(al, off, n, AL_FORWARD, &tx);
d951 1
a951 1
rc = al_traverse(al, off, n, AL_FORWARD, &tx);
@
1.20
log
@added al_traverse_end to API, to allow future cleanup/locking
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d105 2
a106 2
((n) > AL_CHUNK_LEN(alc) - (off) ? \
AL_CHUNK_LEN(alc) - (off) : (n))
d114 5
a118 3
((alc) \
? (alc)->buf->usecount > 1 ? 0 : (alc)->buf->size - (alc)->end \
: 0)
d130 5
a134 3
((alc) \
? (alc)->buf->usecount > 1 ? 0 : (alc)->begin \
: 0)
d145 2
a146 2
static
al_rc_t new_buffer(al_t *al, al_buffer_t **bufp)
d167 2
a168 2
static
al_rc_t dispose_buffer(al_t *al, al_buffer_t *buf)
d186 2
a187 2
static
al_rc_t make_buffer(al_t *al, char *p, size_t n, al_buffer_t **bufp)
d213 1
a213 2
static
struct {
d216 1
a216 2
static
int alc_freecount = 0;
d218 2
a219 2
static
al_rc_t new_chunk(al_t *al, al_buffer_t *buf, al_chunk_t **alcp)
d244 1
a244 1
++buf->usecount;
d250 2
a251 2
static
al_rc_t split_chunk(al_t *al, al_chunk_t *orig, size_t off, al_chunk_t **alcp)
d261 2
a262 1
if (rc != AL_OK) return rc;
d272 2
a273 2
static
void dispose_chunk(al_t *al, al_chunk_t *alc)
d275 12
a286 12
--alc->buf->usecount;
if (alc->buf->usecount == 0)
dispose_buffer(al,alc->buf);
alc->buf = NULL;
/* stop freelist from growing infinitely */
if (alc_freecount >= al->m.max_freechunks) {
(al->m.free)(alc);
} else {
ADDTAIL(&alc_freelist, chunks, alc);
++alc_freecount;
}
d297 2
a298 2
static
al_rc_t al_seek(al_t *al, size_t off, al_chunk_t **alcp, size_t *skipp)
d349 2
a350 2
static
void dump(al_t *al)
d376 2
a377 1
al_rc_t al_create(al_t **alp)
d383 1
a383 1
return AL_RC(AL_ERR_ARG);
d388 1
a388 1
return AL_RC(AL_ERR_MEM);
d411 2
a412 1
al_rc_t al_destroy(al_t *al)
d418 1
a418 1
return AL_RC(AL_ERR_ARG);
d439 2
a440 1
al_rc_t al_append_bytes(al_t *al, const char *src, size_t n)
d450 1
a450 1
return AL_RC(AL_ERR_ARG);
d458 2
a459 1
if (rc != AL_OK) return AL_RC(rc);
d461 2
a462 1
if (rc != AL_OK) return AL_RC(rc);
d488 2
a489 1
al_rc_t al_prepend_bytes(al_t *al, const char *src, size_t n)
d499 1
a499 1
return AL_RC(AL_ERR_ARG);
d509 2
a510 1
if (rc != AL_OK) return AL_RC(rc);
d512 2
a513 1
if (rc != AL_OK) return AL_RC(rc);
d541 2
a542 1
al_rc_t al_attach_buffer(al_t *al, char *p, size_t n)
d550 1
a550 1
return AL_RC(AL_ERR_ARG);
d553 2
a554 1
if (rc != AL_OK) return AL_RC(rc);
d556 2
a557 1
if (rc != AL_OK) return AL_RC(rc);
d577 2
a578 1
al_rc_t al_splice(al_t *al, size_t off, size_t n, al_t *nal, al_t *tal)
d587 1
a587 1
return AL_RC(AL_ERR_ARG);
d597 3
a599 2
if (rc != AL_OK) return AL_RC(rc);
d630 2
a631 1
if (rc != AL_OK) return AL_RC(rc);
d662 1
a662 1
if (rc != AL_OK) {
a664 1
}
d666 1
a666 1
} else {
a667 1
}
d675 1
a675 1
if (skip == 0) {
d677 1
a677 1
} else {
d693 4
a696 4
if (rc != AL_OK) return AL_RC(rc);
} else {
d717 1
a717 1
if (tal == NULL) {
d719 1
a719 1
} else {
a722 1
a733 1
d761 2
a762 1
al_rc_t al_txalloc(al_t *al, al_tx_t **txp)
d777 2
a778 1
al_rc_t al_txfree(al_t *al, al_tx_t *tx)
d790 2
a791 1
al_rc_t al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_tx_t *tx)
d798 2
a799 1
if (rc != AL_OK) return AL_RC(rc);
d814 2
a815 1
al_rc_t al_traverse_next(al_t *al, al_tx_t *tx, al_chunk_t **alcp)
d841 8
a848 8
case AL_FORWARD:
tx->cur = NEXT(tx->cur,chunks);
tx->togo -= step;
break;
case AL_BACKWARD:
tx->cur = PREV(tx->cur,chunks);
tx->togo -= step;
break;
d874 3
a876 2
al_rc_t al_traverse_cb(al_t *al, size_t off, size_t n, al_td_t dir,
al_rc_t (*cb)(al_chunk_t *, void *), void *u)
d883 2
a884 1
if (rc != AL_OK) return AL_RC(rc);
d892 1
a892 1
(void) al_traverse_end(al, &tx, 1);
d907 2
a908 1
al_rc_t al_flatten(al_t *al, size_t off, size_t n, char *dst, size_t *lenp)
d918 2
a919 1
if (rc != AL_OK) return AL_RC(rc);
d924 1
a924 1
memmove(dst, AL_CHUNK_PTR(view,0), step);
d930 1
a930 1
(void) al_traverse_end(al, &tx, 1);
d943 2
a944 1
al_rc_t al_copy(al_t *al, size_t off, size_t n, al_t *tal)
d952 2
a953 1
if (rc != AL_OK) return AL_RC(rc);
d957 1
a957 1
al_append_bytes(tal, AL_CHUNK_PTR(view,0), step);
d960 1
a960 1
(void) al_traverse_end(al, &tx, 1);
d978 3
a980 1
size_t al_bytes(const al_t *al)
d984 3
a986 1
size_t al_chunk_len(al_chunk_t *alc)
d990 3
a992 1
size_t al_chunk_span(al_chunk_t *alc, size_t off, size_t n)
d996 3
a998 1
char *al_chunk_ptr(al_chunk_t *alc, size_t off)
d1006 2
a1007 1
const char *al_error(al_rc_t rc)
d1012 6
a1017 6
case AL_OK: mess = "Everything Ok"; break;
case AL_ERR_ARG: mess = "Invalid Argument"; break;
case AL_ERR_MEM: mess = "Not Enough Memory"; break;
case AL_ERR_EOF: mess = "End Of Data"; break;
case AL_ERR_INT: mess = "Internal Error"; break;
default: mess = "Invalid Result Code"; break;
@
1.19
log
@moved generic list macros to separate header
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d838 11
d872 2
d908 2
d935 2
@
1.18
log
@Ok, as arranged with Michael: use 'assembly line' as the official long name
@
text
@d39 1
a39 132
/****************************************************************************/
#define LIST(elem) \
struct { elem *head, *tail; }
#define NODE(elem) \
struct { elem *next, *prev; }
#define HEAD(q,l) ((q)->l.head)
#define TAIL(q,l) ((q)->l.tail)
#define NEXT(n,l) ((n)->l.next)
#define PREV(n,l) ((n)->l.prev)
#define ISEMPTY(q,l) (HEAD(q,l) == NULL)
#define LISTINIT(q,l) \
do { \
HEAD(q,l) = NULL; \
TAIL(q,l) = NULL; \
} while(0)
#define NODEINIT(n,l) \
do { \
NEXT(n,l) = NULL; \
PREV(n,l) = NULL; \
} while(0)
#define ADDTAIL(q,l,n) \
do { \
if (TAIL(q,l)) { \
NEXT(TAIL(q,l),l) = (n); \
PREV(n,l) = TAIL(q,l); \
} else { \
PREV(n,l) = NULL; \
HEAD(q,l) = (n); \
} \
TAIL(q,l) = (n); \
NEXT(n,l) = NULL; \
} while (0)
#define ADDHEAD(q,l,n) \
do { \
if (HEAD(q,l)) { \
PREV(HEAD(q,l),l) = (n); \
NEXT(n,l) = HEAD(q,l); \
} else { \
NEXT(n,l) = NULL; \
TAIL(q,l) = (n); \
} \
HEAD(q,l) = (n); \
PREV(n,l) = NULL; \
} while (0)
#define REMHEAD(q,l,n) \
do { \
(n) = HEAD(q,l); \
if (n) { \
HEAD(q,l) = NEXT(n,l); \
if (HEAD(q,l)) \
PREV(HEAD(q,l),l) = NULL; \
else \
TAIL(q,l) = NULL; \
} \
} while(0)
#define REMTAIL(q,l,n) \
do { \
(n) = TAIL(q,l); \
if (n) { \
TAIL(q,l) = PREV(n,l); \
if (TAIL(q,l)) \
NEXT(TAIL(q,l),l) = NULL; \
else \
HEAD(q,l) = NULL; \
} \
} while(0)
#define REMOVE(q,l,n) \
do { \
if (PREV(n,l)) \
NEXT(PREV(n,l),l) = NEXT(n,l); \
else \
HEAD(q,l) = NEXT(n,l); \
if (NEXT(n,l)) \
PREV(NEXT(n,l),l) = PREV(n,l); \
else \
TAIL(q,l) = PREV(n,l); \
NEXT(n,l) = NULL; \
PREV(n,l) = NULL; \
} while (0)
#define INSERT(q,l,i,n) \
do { \
if (PREV(i,l)) { \
NEXT(PREV(i,l),l) = (n); \
} else { \
HEAD(q,l) = (n); \
} \
PREV(n,l) = PREV(i,l); \
PREV(i,l) = (n); \
NEXT(n,l) = (i); \
} while (0)
#define APPENDLIST(q1,l,q2) \
do { \
if (TAIL(q1,l)) { \
NEXT(TAIL(q1,l),l) = HEAD(q2,l); \
PREV(HEAD(q2,l),l) = TAIL(q1,l); \
} else { \
HEAD(q1,l) = HEAD(q2,l); \
} \
TAIL(q1,l) = TAIL(q2,l); \
LISTINIT(q2,l); \
} while(0)
#define INSERTLIST(q1,l,i,q2) \
do { \
if (PREV(i,l)) { \
NEXT(PREV(i,l),l) = HEAD(q2,l); \
} else { \
HEAD(q1,l) = HEAD(q2,l); \
} \
PREV(HEAD(q2,l),l) = PREV(i,l); \
NEXT(TAIL(q2,l),l) = (i); \
PREV(i,l) = TAIL(q2,l); \
LISTINIT(q2,l); \
} while(0)
#define FOREACH(q,l,n) for (n = HEAD(q,l); n; n = NEXT(n,l))
#define FOREACHR(q,l,n) for (n = TAIL(q,l); n; n = PREV(n,l))
#define FOREACHD(q,l,n,r) for (n = TAIL(q,l); n && (r = PREV(n,l), 1); n = r)
/****************************************************************************/
@
1.17
log
@decouple pos/neg. offset handling from search direction decision
@
text
@d2 1
a2 1
** OSSP al -- Assembly Lists
d29 1
a29 1
** al.c: assembly lists library implementation
d501 1
a501 1
* allocate an empty assembly list
d512 1
a512 1
/* allocate and initialize new assembly list object */
d684 1
a684 1
* this is the central function to manipulate assembly lists
d876 1
a876 1
* list traversal requires a context. It needs to be
d901 1
a901 1
* initiate list traversal
d922 1
a922 1
* list traversal step
d924 1
a924 1
* return EOF if at end of list
d969 1
a969 1
* full list traversal with callback
d999 1
a999 1
* full list traversal with data copy to linear buffer
d1033 1
a1033 1
* full list traversal with data copy to target assembly list
d1061 1
a1061 1
* al_bytes - total number of bytes in list
@
1.16
log
@using REMTAIL ... closer approximity to the CPU
@
text
@d432 5
a436 1
if (off >= 0) {
d457 1
a457 1
off += al->bytes;
@
1.15
log
@make comment clearer about not resizing chunks in a shared buffer
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d359 5
@
1.14
log
@add the usual amount of license fun
@
text
@d239 5
a243 1
/* number of bytes a chunk can be grown to the end */
d253 5
a257 1
/* number of bytes a chunk can be grown to the beginning */
@
1.13
log
@use default signedness in API and internally
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d1 31
@
1.12
log
@code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d181 1
a181 1
unsigned char *mem;
@
1.11
log
@optimization for short sizes was buggy.
clarify comments
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d831 1
a831 1
al_rc_t al_txalloc(al_t *al, al_tx_t **txpp)
d833 1
a833 1
al_tx_t *txp;
d835 2
a836 2
txp = (al_tx_t*)(al->m.malloc)(sizeof(al_tx_t));
if (txp == NULL)
d839 1
a839 1
*txpp = txp;
d846 1
a846 1
al_rc_t al_txfree(al_t *al, al_tx_t *txp)
d848 1
a848 1
(al->m.free)(txp);
d858 1
a858 1
al_rc_t al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_tx_t *txp)
d862 1
a862 1
txp->cur = NULL;
d864 1
a864 1
rc = al_seek(al, off, &txp->cur, &txp->skip);
d867 2
a868 2
txp->dir = dir;
txp->togo = n;
d880 1
a880 1
al_rc_t al_traverse_next(al_t *al, al_tx_t *txp, al_chunk_t **alcp)
d884 1
a884 1
if (txp->togo <= 0) /* XXX - togo can be negative from bad input */
d887 1
a887 1
if (txp->cur == NULL) /* premature EOF */
d890 3
a892 3
step = AL_CHUNK_LEN(txp->cur);
if (step > txp->togo)
step = txp->togo;
d901 3
a903 3
txp->view = *(txp->cur);
txp->view.begin += txp->skip;
txp->view.end = txp->view.begin + step;
d905 1
a905 1
switch (txp->dir) {
d907 2
a908 2
txp->cur = NEXT(txp->cur,chunks);
txp->togo -= step;
d911 2
a912 2
txp->cur = PREV(txp->cur,chunks);
txp->togo -= step;
d916 1
a916 1
*alcp = &txp->view;
@
1.10
log
@move private al_buffer_t declaration to .c file
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d676 14
a689 3
* if the first chunk is not removed completely it needs to be
* split into two halves to allow insertion of new chunks later
* from nal
d695 1
a695 1
if (ins != NULL && skip > 0 && skip+n < AL_CHUNK_LEN(ins)) {
d774 1
a774 1
* when the insertion point is removed, we have to adjust
d777 2
a778 2
* if the insertion point was the last chunk we get a NULL
* next pointer and the insertion method switches to APPEND
@
1.9
log
@EX support
more comments
insert failure path moved to top of al_splice
chunk copy failure path leaves data structures intact ?!
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d156 3
@
1.8
log
@remove debugging assert()
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d510 3
d522 4
d532 1
a532 1
/* XXX handle error */
d534 1
a534 1
/* XXX handle error */
d556 3
d568 4
d580 1
a580 1
if (rc != AL_OK) return rc;
d582 1
a582 1
if (rc != AL_OK) return rc;
d616 4
d621 1
a621 1
if (rc != AL_OK) return rc;
d623 1
a623 1
if (rc != AL_OK) return rc;
d646 1
a646 1
al_chunk_t *cur, *next;
d648 8
d662 9
a670 1
if (rc != AL_OK) return rc;
d672 19
a690 1
/* as long as there is data to move */
d706 16
a721 2
if (tal != NULL)
al_append_bytes(tal, AL_CHUNK_PTR(cur, skip), step);
d743 6
d758 12
d788 1
a788 8
if (nal && !ISEMPTY(nal,chunks)) {
al_chunk_t *ins;
/* rewind */
rc = al_seek(al, off, &ins, &skip);
if (rc != AL_OK) return rc;
if (ins == NULL) {
d790 1
d792 4
a795 1
* simple case where list end is 'replaced'
d797 1
a797 2
APPENDLIST(al,chunks,nal);
a798 1
d800 1
a800 2
* if beginning and end were in same chunk we have to split this
* chunk in two for a copyless insert operation
d802 1
a802 9
if (skip > 0) {
al_chunk_t *twin;
rc = split_chunk(al, ins, skip, &twin);
if (rc != AL_OK) return rc;
INSERT(al,chunks,ins,twin);
}
INSERTLIST(al,chunks,ins,nal);
d807 1
d823 1
a823 1
return AL_ERR_MEM;
d851 1
a851 1
if (rc != AL_OK) return rc;
d922 1
a922 1
if (rc != AL_OK) return rc;
d931 1
a931 1
return rc;
d953 1
a953 1
if (rc != AL_OK) return rc;
d965 1
a965 1
return rc;
d983 1
a983 1
if (rc != AL_OK) return rc;
d991 1
a991 1
return rc;
@
1.7
log
@al_copy function, like al_flatten but into a target assembly list
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@a0 1
#include
a355 2
assert(NEXT(alc,chunks) == NULL && PREV(alc,chunks) == NULL);
@
1.6
log
@INSERT/REMOVE didn't maintain list header
test code
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d618 1
d620 2
d623 3
d895 26
@
1.5
log
@stop traversal at span boundary
code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d1 1
d5 3
d89 2
d93 4
a101 1
PREV(n,l) = PREV(i,l); \
d103 2
d106 1
d357 2
d428 1
a428 2
#if 0
#include
d433 1
d435 2
a436 1
printf("AL: %x\n", al);
d438 1
a438 1
printf(" C: %x (%d @@ %x + %d < %d)\n",
d441 3
a443 1
cur->begin,cur->end);
d445 1
d477 3
d481 1
d500 1
d684 3
a686 1
if (tal != NULL) {
a688 2
} else {
dispose_chunk(al, cur);
@
1.4
log
@code cleanup
get rid of AL_ALL_BYTES, not very useful
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d773 4
a776 1
if (txp->cur == NULL)
d852 2
@
1.3
log
@splice operation
traversal needs alloc/free function for context
lost of comments
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d5 2
d128 2
d191 1
a191 1
((n) == AL_BYTES_ALL || (n) > AL_CHUNK_LEN(alc) - (off) ? \
d364 1
d371 1
a371 1
size_t pos;
d378 2
a379 1
if (pos <= off && off < pos+chunksize) {
d384 9
a392 3
if (pos+chunksize >= off)
return AL_ERR_EOF;
pos += chunksize;
d399 1
d401 1
a401 1
if (pos <= off && off < pos+chunksize) {
d406 2
a407 2
if (pos+chunksize < off)
return AL_ERR_EOF;
d432 1
a432 1
/******************************************************************/
a604 5
/* simplify API */
if (n == AL_BYTES_ALL) n = al->bytes - off;
pos = off;
d609 1
a609 1
rc = al_seek(al, pos, &cur, &skip);
d613 1
a672 3
if (cur == NULL)
break;
a712 1
a750 2
if (n == AL_BYTES_ALL) n = al->bytes - off;
d893 19
@
1.2
log
@added memory allocation policy
needs to pass through context to lower functions
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d15 2
d87 35
a121 1
#define ISEMPTY(q,l) (HEAD(q,l) == NULL)
d212 1
d318 21
d422 1
a422 1
* allocate an empty assembly line
d433 1
a433 1
/* allocate and initialize new assembly line object */
d475 3
d514 3
d555 8
d581 6
a586 1
al_rc_t al_splice(al_t *al, size_t off, size_t n, al_t *tal)
d590 1
a590 1
size_t skip, len, step;
d592 1
d595 7
a601 1
rc = al_seek(al, off, &cur, &skip);
d603 3
a605 3
printf("initial seek %d -> %p + %d\n",off,cur,skip);
while (n > 0) {
/* check if a partial chunk was selected */
d608 6
d615 4
a618 5
/* copy span from src chunk to target */
step = len - skip;
if (n < step)
step = n;
printf("partial copy (%p + %d) + %d bytes\n",cur,skip,step);
d621 7
a627 1
/* cut span from src chunk */
a628 1
printf("shrink at begin\n");
a632 1
printf("align chunk buffer (%d + %d) <- %d\n",skip,step,len-(skip+step));
a638 1
printf("shrink at end\n");
d641 1
d643 6
a649 1
printf("hand over chunk %d\n",step);
d656 1
a656 1
dispose_chunk(al,cur);
d658 1
d661 1
a661 1
off += step;
d664 3
d669 56
a724 1
return AL_ERR_INT;
d727 4
a730 1
al_rc_t al_truncate(al_t *al, size_t off, size_t n)
d732 2
a733 1
return al_splice(al, off, n, NULL);
d736 6
d751 1
a751 1
if (rc != AL_OK) return AL_OK;
d759 7
d803 8
d815 1
a815 1
al_tx_t tx;
d833 8
a840 1
al_rc_t al_flatten(al_t *al, size_t off, size_t n, char *dst)
d843 1
a843 1
al_tx_t tx;
d845 1
a845 1
size_t step;
d850 1
d854 2
a855 1
dst += step;
d857 1
d865 10
a878 1
a882 1
a886 1
@
1.1
log
@first iteration through buffer data type
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d105 9
d117 1
a173 3
#define AL_NEW_BUFFERSIZE 100
#define AL_MAX_FREECHUNKS 500
d179 1
a179 1
al_rc_t new_buffer(al_buffer_t **bufp)
d181 1
a181 1
size_t n = AL_NEW_BUFFERSIZE;
d184 1
a184 1
if ((buf = (al_buffer_t *)malloc(sizeof(al_buffer_t))) == NULL)
d187 2
a188 2
if ((buf->mem = malloc(n)) == NULL) {
free(buf);
d201 1
a201 1
al_rc_t dispose_buffer(al_buffer_t *buf)
d208 1
a208 1
free(buf->mem);
d210 1
a210 1
free(buf);
d220 1
a220 1
al_rc_t make_buffer(char *p, size_t n, al_buffer_t **bufp)
d224 1
a224 1
if ((buf = (al_buffer_t *)malloc(sizeof(al_buffer_t))) == NULL)
d254 1
a254 1
al_rc_t new_chunk(al_buffer_t *buf, al_chunk_t **alcp)
d259 1
a259 1
if ((alc = (al_chunk_t *)malloc(sizeof(al_chunk_t))) == NULL) {
d261 1
a261 1
dispose_buffer(buf);
d281 1
a281 1
void dispose_chunk(al_chunk_t *alc)
d285 1
a285 1
dispose_buffer(alc->buf);
d289 2
a290 2
if (alc_freecount >= AL_MAX_FREECHUNKS) {
free(alc);
d376 1
d383 8
d407 1
a407 1
dispose_chunk(cur);
d411 1
d430 1
a430 1
rc = new_buffer(&buf);
d432 1
a432 1
rc = new_chunk(buf,&cur);
d468 1
a468 1
rc = new_buffer(&buf);
d470 1
a470 1
rc = new_chunk(buf,&cur);
d497 1
a497 1
rc = make_buffer(p, n, &buf);
d499 1
a499 1
rc = new_chunk(buf, &cur);
d558 1
a558 1
dispose_chunk(cur);
@