user6552697
user6552697

Reputation:

return address of part of a circular array

So i have a circular array of max size 2097152 and i want it to fill up to 524288 and return the address that holds that 524288 indices. Then fills up another 524288 and do the same. and keeps doing that since it's a circular array.

I am getting stream of data via TCP. This data comes in different sizes, but for now I'm just trying to fill up my array with numbers.
I'm not sure how to approach this. I have this so far:

    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <arpa/inet.h>
    #include <stdbool.h>




    typedef struct circular_buffer
    {
        void *buffer;     // data buffer
        void *buffer_end; // end of data buffer
        size_t capacity;  // maximum number of items in the buffer
        size_t count;     // number of items in the buffer
        size_t sz;        // size of each item in the buffer
        void *head;       // pointer to head
        void *tail;       // pointer to tail
    } circular_buffer;

    void cb_init(circular_buffer *cb, size_t capacity, size_t sz)
    {
        cb->buffer = malloc(capacity * sz);
        if(cb->buffer == NULL)
            {
            printf("myError: Buffer returned Null");
            }
        cb->buffer_end = (char *)cb->buffer + capacity * sz;
        cb->capacity = capacity;
        cb->count = 0;
        cb->sz = sz;
        cb->head = cb->buffer;
        cb->tail = cb->buffer;
    }

    void cb_free(circular_buffer *cb)
    {
        free(cb->buffer);
        // clear out other fields too, just to be safe
    }

    void cb_push_back(circular_buffer *cb, const void *item)
    {
        if(cb->count == cb->capacity)
            // handle error
        memcpy(cb->head, item, cb->sz);
        cb->head = (char*)cb->head + cb->sz;
        if(cb->head == cb->buffer_end)
            cb->head = cb->buffer;
        cb->count++;
    }



int main()
{
 int *arr = malloc (BUFFER_LEN * sizeof *arr);
int i;
for(i = 0; i <= BUFFER_LEN; i++) { arr[i] = i; }

   return(0);
}

Upvotes: 0

Views: 371

Answers (2)

Craig Estey
Craig Estey

Reputation: 33631

I've done a few of these circular buffer / ring queues before. Below is one of the versions I've used. The source code is complete and has a demo/diagnostic program. It should be buildable and runnable without [much :-)] change.

The central core of this, embodied in the .h file has been floating around my code base for 10-20 years, so it's got some mileage on it. Because of this, it has a few things that I've added based on my actual usage and experience with it.

There are a few differences from your version. Not necessarily better or worse--just different. Hopefully, this will give you some ideas for your own code.

For one, there is only one pointer to the start of the queue. The enqueue element [which you named cb_head] is an index rather than a pointer. Likewise for the dequeue [cb_tail]. From my experience, this makes the code a bit simpler, is on-par speedwise [and can sometimes be faster].

Although I have versions that use pointers to everything, they have pointers to a specific [struct] type, rather than void * pointers and a "sizeof" element. But, to do this in C, requires a lot of CPP macro [or metaprogramming] trickery, to get the effect of a C++ template.

One of the other reasons for using indexes vs. pointers is creating multithread/thread safe queues. This hasn't been designed into this particular version, but there is a cursory example with qrngnew_lck that would use a lock (e.g. pthread_mutex_lock/pthread_mutex_unlock).

Also, as an alternative to a mutex, it is possible to use primitives from stdatomic.h (e.g. atomic_compare_exchange*) to change the enqueue/dequeue values. It is much easier to use this if these values are int vs void *


When dealing with a lot of data (e.g. from recv), what's most useful is to know how many cells can be copied in a single chunk (i.e. memcpy), rather than doing individual pushes and pops [which is slow].

Also, maintaining a separate count of number of elements in queue isn't necessary as this is easily calculated from the enqueue and dequeue values.

Things of interest are:

  1. total number of free cells available to enqueue data
  2. number of contiguous free cells available for a single memcpy
  3. total number of filled cells pending to be dequeued
  4. number of contiguous filled cells pending that can extracted with a single memcpy

Anyway, the code is below. It is three files: qrng.h, qrng.c, and qrngdemo.c.

Sorry about the qrng*. It's a personal signature style (i.e. "quirk"). It could just as easily have been ring everywhere [but, because I have several different versions, I use this naming to avoid collisions in C's namespace]. It could also have been [say] cb everywhere :-)


qrng.h:

// ovrlib/qrng.h -- ring queue control

#ifndef _ovrlib_qrng_h_
#define _ovrlib_qrng_h_

#define QRNGMAGIC       0xDEAFDEAD

#define QRNGINLINE      static inline

#define _QRNGOFF(_itm) \
    ((long) _itm)
#define QRNGOFF(_qrng,_itm) \
    _QRNGOFF(_qrng->_itm)

#define QRNG_FMT \
    "deq=%ld enq=%ld pend=%ld/%ld avail=%ld/%ld qmax=%ld"

#define QRNG_PRT(_qrng) \
    QRNGOFF(_qrng,qrng_deq), \
    QRNGOFF(_qrng,qrng_enq), \
    _QRNGOFF(qrng_pend_buf(_qrng)), \
    _QRNGOFF(qrng_pend_tot(_qrng)), \
    _QRNGOFF(qrng_avail_buf(_qrng)), \
    _QRNGOFF(qrng_avail_tot(_qrng)), \
    QRNGOFF(_qrng,qrng_qmax)

// pointer to queue data item
// NOTES:
// (1) _always_ use void *
// (2) the way this is used, setting this to _anything_ else will _not_ work
typedef void *queitm_p;
typedef const void *queitm_pc;

// queue index
// NOTES:
// (1) _must_ be signed
// (2) for most queues, an int is sufficient
#ifdef QRNG_BIGIDX
typedef long qidx_t;
#else
typedef int qidx_t;
#endif
typedef long qlen_t;

typedef unsigned int u32;

typedef struct quering_struct quering_t;
typedef quering_t *quering_p;
typedef const quering_t *quering_pc;
struct quering_struct {
    u32 qrng_magic;                     // magic number
    u32 qrng_stat;                      // status

    int qrng_algn[2];                   // align to 64 byte boundary

    // WARNING:
    // (1) accesses to these via sysxchgl require them in
    //     _exactly_ this order -- do _not_ reorder these
    // (2) for 64b mode (cmpxchg16b), these must be aligned to a 16 byte
    //     boundary
    qidx_t qrng_deq;                    // dequeue pointer
    qidx_t qrng_enq;                    // enqueue pointer

    qidx_t qrng_siz;                    // size of queitm_t

    queitm_p qrng_base;                 // base address of ring buffer
    qidx_t qrng_qmax;                   // number of queue elements
};

// equates to status
#define QRNGALLOC       (1u << 0)       // 1=qrng_base is allocated on heap

// qrng_len -- get byte offset/length from index/count
QRNGINLINE qlen_t
qrng_len(quering_p qrng,qidx_t idx)
{
    qlen_t len;

    len = idx;
    len *= qrng->qrng_siz;

    return len;
}

// qrng_ptr -- get flat pointer to queue element
QRNGINLINE queitm_p
qrng_ptr(quering_p qrng,qidx_t idx)
{
    queitm_p ptr;

    ptr = qrng->qrng_base;
    ptr += qrng_len(qrng,idx);

    return ptr;
}

// qrng_wrap_dec -- wrap queue index after decrement
QRNGINLINE qidx_t
qrng_wrap_dec(quering_p qrng,qidx_t qitm,qidx_t inc)
{

    qitm -= inc;

    if (qitm < 0)
        qitm += qrng->qrng_qmax;

    return qitm;
}

// qrng_wrap_inc -- wrap queue index after increment
QRNGINLINE qidx_t
qrng_wrap_inc(quering_p qrng,qidx_t qitm,qidx_t inc)
{
    qidx_t dif;

    qitm += inc;

    dif = qitm - qrng->qrng_qmax;
    if (dif >= 0)
        qitm = dif;

    return qitm;
}

// qrng_reset -- reset queue pointers
QRNGINLINE void
qrng_reset(quering_p qrng)
{

    qrng->qrng_enq = 0;
    qrng->qrng_deq = 0;
}

// qrng_full -- decide if qrng queue is full
// RETURNS: 1=full
QRNGINLINE int
qrng_full(quering_p qrng)
{
    qidx_t qenq;

    qenq = qrng_wrap_inc(qrng,qrng->qrng_enq,1);

    return (qenq == qrng->qrng_deq);
}

// _qrng_empty -- decide if qrng queue is empty
// RETURNS: 1=empty
QRNGINLINE int
_qrng_empty(quering_p qrng,qidx_t enq)
{

    return (qrng->qrng_deq == enq);
}

// qrng_empty -- decide if qrng queue is empty
// RETURNS: 1=empty
QRNGINLINE int
qrng_empty(quering_p qrng)
{

    return _qrng_empty(qrng,qrng->qrng_enq);
}

// qrng_avail_buf -- amount that can be added by single memcpy
QRNGINLINE qidx_t
qrng_avail_buf(quering_p qrng)
{
    qidx_t len;

    len = qrng->qrng_deq - qrng->qrng_enq;

    if (len <= 0) {
        len = qrng->qrng_qmax - qrng->qrng_enq;
        if (qrng->qrng_deq == 0)
            --len;
    }
    else
        --len;

    return len;
}

// qrng_avail_tot_ptr -- total amount that can be added
QRNGINLINE qidx_t
qrng_avail_tot_ptr(quering_p qrng,qidx_t deq,qidx_t enq)
{
    qidx_t len;

    len = deq - enq;

    if (len <= 0)
        len += qrng->qrng_qmax;

    --len;

    return len;
}

// qrng_avail_tot -- total amount that can be added
QRNGINLINE qidx_t
qrng_avail_tot(quering_p qrng)
{

    return qrng_avail_tot_ptr(qrng,qrng->qrng_deq,qrng->qrng_enq);
}

// qrng_pend_buf -- amount that may be dequeued by single memcpy
QRNGINLINE qidx_t
qrng_pend_buf(quering_p qrng)
{
    qidx_t len;

    len = qrng->qrng_enq - qrng->qrng_deq;

    if (len < 0)
        len = qrng->qrng_qmax - qrng->qrng_deq;

    return len;
}

// qrng_pend_tot -- total amount that may be dequeued
QRNGINLINE qidx_t
qrng_pend_tot(quering_p qrng)
{
    qidx_t len;

    len = qrng->qrng_enq - qrng->qrng_deq;

    if (len < 0)
        len += qrng->qrng_qmax;

    return len;
}

// qrng_deq_buf -- dequeue buffer from qrng queue
QRNGINLINE void
qrng_deq_buf(quering_p qrng,qidx_t inclen)
// inclen -- amount to increment
{

    qrng->qrng_deq = qrng_wrap_inc(qrng,qrng->qrng_deq,inclen);
}

// qrng_enq_buf -- enqueue buffer into qrng queue
QRNGINLINE void
qrng_enq_buf(quering_p qrng,qidx_t inclen)
// inclen -- amount to increment
{

    qrng->qrng_enq = qrng_wrap_inc(qrng,qrng->qrng_enq,inclen);
}

// /home/cae/OBJ/ovrgen/ovrlib/qrng.proto -- prototypes

// FILE: /home/cae/preserve/ovrstk/ovrlib/qrng.c
// ovrlib/qrng -- ring queue common control

    // _qrngnoalloc -- handle alloc failure
    void
    _qrngnoalloc(quering_p qrng,int sverr);

    // qrng_setup -- passive setup
    // RETURNS: 1=initialized
    int
    qrng_setup(quering_p qrng,queitm_p bp,qidx_t siz,qidx_t cnt);

    // qrng_alloc -- allocate ring queue
    queitm_p
    qrng_alloc(quering_p qrng,qidx_t cnt);

    // qrng_free -- free queue
    void
    qrng_free(quering_p qrng);

    // qrng_deq_sgl -- dequeue single element from qrng queue
    queitm_p
    qrng_deq_sgl(quering_p qrng);

    // qrng_enq_sgl -- enqueue single element into qrng queue
    queitm_p
    qrng_enq_sgl(quering_p qrng,queitm_p qitm);

    // qrngnew_lck -- enqueue multiple items into qrng queue (syslock)
    // RETURNS: pointer to items to store (or NULL)
    queitm_p
    qrngnew_lck(quering_p qrng,qidx_t cnt,quering_p rlsdeq);

    // _qrngnew_init -- do special type-specific initialization
    void
    _qrngnew_init(queitm_p qitm);

    // _qrngnew_onfull -- decide if capture is stopped because queue is full
    queitm_p
    _qrngnew_onfull(quering_p qrng,qidx_t rtn);

    // qrngcowbrk -- break copy-on-write
    void
    qrngcowbrk(quering_p qrng);

    // qrngfault -- output fault
    void
    qrngfault(quering_p qrng,const char *fmt,...) __attribute__((__format__(__printf__,2,3)));

#endif

qrng.c:

// ovrlib/qrng -- ring queue common control

#include <qrng.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>

#if 0
#define zprt(_lvl,_fmt...)      fprintf(stderr,_fmt)
#else
#define zprt(_lvl,_fmt...)      /**/
#endif

// _qrngnoalloc -- handle alloc failure
void
_qrngnoalloc(quering_p qrng,int sverr)
{

    qrngfault(qrng,"_qrngnoalloc: unable to allocate buffer -- %s\n",
        strerror(sverr));
}

// qrng_setup -- passive setup
// RETURNS: 1=initialized
int
qrng_setup(quering_p qrng,queitm_p bp,qidx_t siz,qidx_t cnt)
{
    int initflg;

#ifdef CPLXCVTLNG
    if ((CPLXCVTLNG(qrng) % 16) != 0)
        qrngfault("qrngsetup: alignment fault -- qrng=%p\n",qrng);
#endif

    do {
        initflg = (qrng->qrng_magic != QRNGMAGIC);

        if (initflg)
            memset(qrng,0,sizeof(quering_t));

        qrng->qrng_magic = QRNGMAGIC;
        qrng->qrng_siz = siz;

        // allocate space for queue
        if (bp == NULL)
            bp = qrng_alloc(qrng,cnt);
        else
            qrng_free(qrng);

        qrng->qrng_base = bp;
        qrng->qrng_qmax = cnt;

        // break copy-on-write
        qrngcowbrk(qrng);
    } while (0);

    qrng_reset(qrng);

    return initflg;
}

// qrng_alloc -- allocate ring queue
queitm_p
qrng_alloc(quering_p qrng,qidx_t cnt)
{
    queitm_p qitm;
    int sverr;

    do {
        qitm = qrng->qrng_base;

        // don't realloc if old and new sizes match -- just reset the pointers
        if (qitm != NULL) {
            if (cnt == qrng->qrng_qmax) {
                break;
            }
        }

        // free the old queue
        qrng_free(qrng);

        // allocate the queue
        qitm = calloc(cnt,qrng->qrng_siz);
        sverr = errno;

        // fault on alloc failure
        if (qitm == NULL)
            _qrngnoalloc(qrng,sverr);

        qrng->qrng_stat |= QRNGALLOC;
    } while (0);

    qrng_reset(qrng);

    return qitm;
}

// qrng_free -- free queue
void
qrng_free(quering_p qrng)
{
    queitm_p qitm;

    do {
        qitm = qrng->qrng_base;

        if (qitm == NULL) {
            break;
        }

        if (qrng->qrng_stat & QRNGALLOC) {
            free(qitm);
        }
    } while (0);

    qrng->qrng_base = NULL;
    qrng->qrng_stat &= ~QRNGALLOC;

}

// qrng_deq_sgl -- dequeue single element from qrng queue
queitm_p
qrng_deq_sgl(quering_p qrng)
{
    qidx_t deq;
    queitm_p qrtn;

    do {
        if (qrng_empty(qrng)) {
            qrtn = NULL;
            break;
        }

        deq = qrng->qrng_deq;
        qrtn = qrng_ptr(qrng,deq);

        qrng->qrng_deq = qrng_wrap_inc(qrng,deq,1);
    } while (0);

    return qrtn;
}

// qrng_enq_sgl -- enqueue single element into qrng queue
queitm_p
qrng_enq_sgl(quering_p qrng,queitm_p qitm)
// qitm -- item to enqueue (if NULL, caller will do copy on return)
{
    qidx_t enq;
    queitm_p qrtn;

    do {
        if (qrng_full(qrng)) {
            qrtn = NULL;
            break;
        }

        enq = qrng->qrng_enq;

        qrtn = qrng_ptr(qrng,enq);

        // we give the caller the option of doing the copy manually or letting
        // us do it
        if (qitm != NULL)
            memcpy(qrtn,qitm,qrng->qrng_siz);

        qrng->qrng_enq = qrng_wrap_inc(qrng,enq,1);
    } while (0);

    return qrtn;
}

// qrngnew_lck -- enqueue multiple items into qrng queue (syslock)
// RETURNS: pointer to items to store (or NULL)
queitm_p
qrngnew_lck(quering_p qrng,qidx_t cnt,quering_p rlsdeq)
{
    qidx_t nenq;
    qidx_t ndeq;
    qidx_t odeq;
    qidx_t oenq;
    int stopflg;
    int wflg;
    int dflg;
    int ovflg;
    queitm_p optr;

    stopflg = 0;

    // lock it
    //SYSLOCKQ(&qrng->qrng_lock,0);

    do {
        // grab the old values
        odeq = qrng->qrng_deq;
        oenq = qrng->qrng_enq;

        do {
            // point to one beyond where we wish to store
            nenq = qrng_wrap_inc(qrng,oenq,cnt);

            // decide if we wrapped the enqueue pointer
            wflg = (nenq < oenq);

            // decide if dequeue increment is positive (non-negative)
            dflg = (nenq >= odeq);

            // decide on overflow
            // NOTE: there is an elaborate explanation for the overflow
            // logic in qrng.m5m
            if (oenq >= odeq)
                ovflg = wflg && dflg;
            else
                ovflg = (wflg != dflg);

            // [initial] filling of queue:
            // (1) enq was higher than deq and it did _not_ wrap
            // (2) enq was lower than deq and it did _not_ touch/go over
            if (! ovflg) {
                ndeq = odeq;
                break;
            }

            // advance the dequeue pointer to make room
            ndeq = qrng_wrap_inc(qrng,nenq,1);
        } while (0);

        // allow caller to "release" the dequeued nodes
        if (rlsdeq != NULL) {
            rlsdeq->qrng_deq = odeq;
            rlsdeq->qrng_enq = ndeq;
        }

        // lay down the new pointers
        qrng->qrng_enq = nenq;
        qrng->qrng_deq = ndeq;
    } while (0);

    // zap the type (ASAP)
    // NOTE: there is a slight (virtually non-existent) race condition here
    // which only occurs if we get held off too long and a dump begins
    do {
        if (stopflg) {
            optr = _qrngnew_onfull(qrng,oenq);
            break;
        }

        optr = qrng_ptr(qrng,oenq);
        _qrngnew_init(optr);
    } while (0);

    // unlock it
    //SYSUNLOCKQ(&qrng->qrng_lock);

    return optr;
}

// _qrngnew_init -- do special type-specific initialization
void
_qrngnew_init(queitm_p qitm)
{
    //ARGV_USED(qitm);
}

// _qrngnew_onfull -- decide if capture is stopped because queue is full
queitm_p
_qrngnew_onfull(quering_p qrng,qidx_t rtn)
{
    queitm_p ptr;

    qrngfault(qrng,"qrngnew: stop on full\n");

    ptr = NULL;

    return ptr;
}

// qrngcowbrk -- break copy-on-write
void
qrngcowbrk(quering_p qrng)
{
    qlen_t len;

    len = qrng_len(qrng,qrng->qrng_qmax);
    if (len > 0)
        memset(qrng->qrng_base,0,len);
}

// qrngfault -- output fault
void
qrngfault(quering_p qrng,const char *fmt,...)
{
    va_list ap;

    va_start(ap,fmt);
    vfprintf(stderr,fmt,ap);
    va_end(ap);

    exit(1);
}

qrngdemo.c:

// qrngdemo/qrngdemo -- test/demo program for qrng

#include <qrng.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int opt_v;
qidx_t opt_M;
int opt_T;

#define dbgprt(_fmt...) \
    do { \
        if (opt_v) \
            printf(_fmt); \
    } while (0)

#define fault(_fmt...) \
    do { \
        printf(_fmt); \
        exit(1); \
    } while (0)

quering_t sampque;

#ifndef MAXCNT
#if 0
#define MAXCNT      524288
#else
#define MAXCNT      337
#endif
#endif

typedef struct {
    unsigned int samp_pos;
    unsigned int samp_neg;
} sample_t;
typedef sample_t *sample_p;

unsigned int filloff;
unsigned int cmpoff;
sample_p temp;

// sampsetup -- do setup of sample queue
void
sampsetup(quering_p sampq)
{

    if (opt_M < 3)
        opt_M = 3;

    qrng_setup(sampq,NULL,sizeof(sample_t),opt_M);
    temp = calloc(opt_M + 10,sizeof(sample_t));
}

// randval -- get random count
qidx_t
randval(qidx_t max)
{
    qidx_t cnt;

    cnt = rand() % opt_M;
    if (cnt <= 0)
        cnt = 1;

    if (cnt > max)
        cnt = max;

    return cnt;
}

// fill -- fill queue
void
fill(quering_p sampq)
{
    sample_p samp;
    qidx_t addcnt;
    qidx_t maxcnt;
    qidx_t xcnt;
    qidx_t idx;

    maxcnt = qrng_avail_tot(sampq);
    addcnt = randval(maxcnt);

    dbgprt("fill: ENTER maxcnt=%ld addcnt=%ld\n",
        _QRNGOFF(maxcnt),_QRNGOFF(addcnt));

    // fill linear buffer
    for (idx = 0;  idx < addcnt;  ++idx) {
        samp = &temp[idx];
        samp->samp_pos = filloff;
        samp->samp_neg = ~filloff;
        filloff += 1;
    }

    dbgprt("fill: TEMP %8.8X/%8.8X\n",
        temp[0].samp_pos,temp[addcnt - 1].samp_pos);

    // copy linear buffer into ring queue
    for (idx = 0;  addcnt > 0;  idx += xcnt, addcnt -= xcnt) {
        xcnt = qrng_avail_buf(sampq);
        if (xcnt > addcnt)
            xcnt = addcnt;
        if (xcnt <= 0)
            break;

        dbgprt("fill: COPY %8.8X/%8.8X -- xcnt=%ld " QRNG_FMT "\n",
            temp[idx].samp_pos,temp[idx + xcnt - 1].samp_pos,
            _QRNGOFF(xcnt),
            QRNG_PRT(sampq));

        memcpy(qrng_ptr(sampq,sampq->qrng_enq),&temp[idx],qrng_len(sampq,xcnt));

        qrng_enq_buf(sampq,xcnt);
    }

    dbgprt("fill: EXIT " QRNG_FMT "\n",QRNG_PRT(sampq));
}

// cmp -- compare queue
void
cmp(quering_p sampq)
{
    sample_p samp;
    qidx_t cmpcnt;
    qidx_t maxcnt;
    qidx_t xcnt;
    qidx_t chkcnt;
    qidx_t idx;

    maxcnt = qrng_pend_tot(sampq);
    cmpcnt = randval(maxcnt);

    dbgprt("cmp: ENTER maxcnt=%ld cmpcnt=%ld\n",
        _QRNGOFF(maxcnt),_QRNGOFF(cmpcnt));

    // copy data from ring queue into linear buffer
    chkcnt = 0;
    for (idx = 0;  cmpcnt > 0;  idx += xcnt, cmpcnt -= xcnt) {
        xcnt = qrng_pend_buf(sampq);
        if (xcnt > cmpcnt)
            xcnt = cmpcnt;
        if (xcnt <= 0)
            break;
        chkcnt += xcnt;

        memcpy(&temp[idx],qrng_ptr(sampq,sampq->qrng_deq),qrng_len(sampq,xcnt));

        dbgprt("cmp: COPY %8.8X/%8.8X -- xcnt=%ld " QRNG_FMT "\n",
            temp[idx].samp_pos,temp[idx + xcnt - 1].samp_pos,
            _QRNGOFF(xcnt),
            QRNG_PRT(sampq));

        qrng_deq_buf(sampq,xcnt);
    }

    if (chkcnt > 0)
        dbgprt("cmp: TEMP %8.8X/%8.8X chkcnt=%ld\n",
            temp[0].samp_pos,temp[chkcnt - 1].samp_pos,_QRNGOFF(chkcnt));

    // check linear buffer
    for (idx = 0;  idx < chkcnt;  ++idx) {
        samp = &temp[idx];
        if ((samp->samp_pos != cmpoff) || (samp->samp_neg != ~cmpoff))
            fault("cmp: failure -- idx=%d samp_pos=%8.8X cmpoff=%8.8X\n",
                idx,samp->samp_pos,cmpoff);
        cmpoff += 1;
    }

    dbgprt("cmp: EXIT " QRNG_FMT "\n",QRNG_PRT(sampq));
}

// main -- main program
int
main(int argc,char **argv)
{
    char *cp;

    --argc;
    ++argv;

    opt_M = MAXCNT;
    opt_T = 10000000;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'M':
            opt_M = strtol(cp,&cp,10);
            break;

        case 'T':
            opt_T = strtol(cp,&cp,10);
            break;

        case 'v':
            opt_v = 1;
            break;
        }
    }

    sampsetup(&sampque);

    for (int iter = opt_T;  iter >= 0;  --iter) {
        fill(&sampque);
        cmp(&sampque);
    }

    qrng_free(&sampque);

    return 0;
}

Upvotes: 0

dave
dave

Reputation: 4922

You can return the start of your data with the address-of operator (&) and access this like an array. e.g.

char *fill_cb(circular_buffer *cb, char *buf, size_t sz)
{
    /* Assume there is room in the buffer: caller must check before calling this function */
    if(cb->tail + sz < cb->buffer_end) {
        memcpy(cb->tail, buf, sz);
        cb->tail += sz;
        cb->count += sz;
        return cb->tail - sz;
    } else {
        size_t tail_room = cb->buffer_end - cb->tail;
        memcpy(cb->tail, buf, tail_room);
        memcpy(cb->buffer, buf + tail_room, sz - tail_room);
        cb->tail = cb->buffer + sz - tail_room;
        return cb->buffer_end - tail_room;
    }
}

Now you can use this pointer and access the memory in the circular buffer much like an array

e.g.

my_data = fill_cb(cb, buf, 20);
do_stuff(my_data[10]);

However, this will only work when you didn't wrap! The array access expects memory to be contiguous. But we wrapped inside the circular buffer. So returning a pointer to the start of the data inserted isn't useful to the using program. You need to write access methods to get the data out of the circular buffer. In C++ you might overload [] to make it look like an array. In C you need to write functions for these.

Basically, you are hoping that there can be a memory region which is wrapped like your diagram, but memory is flat and if you return the address of the start of the data and access from there continuously then you will read past the end of the circular buffer (and in to undefined behaviour).

Upvotes: 0

Related Questions