123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- #include "circlebuffer.h"
- #include <assert.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h> /* memory copy */
- #include "duck_mem.h"
- /* this is just a debugging trick so that we can "see" the free space */
- void* circleread_memcpy(void* dst, void* src, int64_t count);
- void* circleread_memcpy(void* dst, void* src, int64_t count)
- {
- return duck_memcpy64(dst, src, count);
- }
- void CircleReport(const CircleBuffer_t* cb, const char* title)
- {
- printf("-----(%s)------\n", title);
- printf("max Size cb = %ld\n", cb->bufSize);
- printf("fills at = %ld\n", cb->bufSize * cb->percent / 100 );
- printf("Current amount = %ld, level = %ld\n", cb->count, cb->count * 100 / cb->bufSize);
- }
- int ForwardBuffer(CircleBuffer_t* cb, int64_t len)
- {
- if (len >= (int64_t)cb->count)
- return -1;
-
- if ( (cb->head + len) < cb->bufSize )
- cb->head += (int)len;
-
- else
- cb->head = (int)len - (cb->bufSize - cb->head);
-
- cb->count -= (int)len;
-
- return 0;
- }
- int RewindBuffer(CircleBuffer_t* cb, int64_t len)
- {
- if (len >= (int64_t)(cb->bufSize - cb->count) )
- return -1; /* not enough history in buffer ! */
- if (cb->head <= (size_t)len)
- {
- if (cb->wrapped == 0)
- return -1;
-
- cb->head = cb->bufSize - ((int)len - cb->head);
- cb->count += (int)len;
- return 0;
- }
- else
- {
- cb->head -= (int)len;
- cb->count += (int)len;
- }
-
- return 0;
- }
- void destroyCircleBuffer(CircleBuffer_t* cb)
- {
- assert(cb);
- if (cb->buffer)
- free(cb->buffer);
-
- if (cb->maxChunk)
- free(cb->maxChunk);
- }
- int resetCircleBuffer(CircleBuffer_t* cb)
- {
- cb->count = 0;
- cb->bytesConsumed = 0;
- cb->wrapped = 0;
- cb->starvedBytes = 0;
- cb->starvedRequests = 0;
-
- return 0;
- }
- int initCircleBuffer(
- CircleBuffer_t* cb,
- size_t countRecords,
- int percent,
- size_t maxChunk,
- FuncLock_t lock,
- FuncLock_t unlock
- )
- {
- assert(cb);
-
- cb->buffer = (unsigned char * ) calloc(1, countRecords);
-
- cb->maxChunk = (unsigned char *) calloc(1, maxChunk);
- cb->maxChunkLen = maxChunk;
-
- if (cb->buffer)
- {
- cb->head = cb->count = 0;
- cb->balance = 0;
- cb->bufSize = countRecords;
- cb->bytesConsumed = 0;
- cb->muted = false;
- cb->percent = percent;
- cb->wrapped = 0;
- cb->lock = lock;
- cb->unlock = unlock;
- return 0;
- }
- else
- {
- return -1; /* error */
- }
-
- }
- /* return zero if plenty of room and success */
- /*-------------------------------------------*/
- /* free space nested in the middle of the buffer is consider endSpace */
- /* and when free space nested in middle, startSpace is considered to be zero */
- /*---------------------------------------------------------------------------*/
- int addToCircleBuffer(CircleBuffer_t* cb, void* data, size_t requestSpace)
- {
- int64_t freeSpace; /* count total free space in buffer */
- int64_t head = cb->head; /* offset start of valid data */
- int64_t tail = (cb->head + cb->count) % cb->bufSize; /* offest first free byte after valid data */
- int64_t endSpace;
- freeSpace = cb->bufSize - cb->count;
-
- /* if not enough room to do the add */
- /*----------------------------------*/
- if (requestSpace > freeSpace)
- {
- assert(0);
- return CB_FULL;
- }
-
- endSpace = cb->bufSize - tail;
-
- if (tail >= head && requestSpace > endSpace) /* additional data write will wrap */
- {
- duck_memcpy64(&cb->buffer[tail], data, endSpace);
- duck_memcpy64(
- cb->buffer,
- (unsigned char *)data+endSpace,
- requestSpace - endSpace);
- }
- else /* existing data wrapped around from end of buffer through beginning of buffer. */
- {
- memcpy(&cb->buffer[tail], data, requestSpace);
- }
-
- cb->count += requestSpace;
- cb->balance += 1;
- return 0; /* -1 will mean error,m zero is OK */
- }
- /* get info need so we can write direct as in memcpy into the circle buffer */
- /*--------------------------------------------------------------------------*/
- void FreeWrapless(const CircleBuffer_t* cb, void* handle, int64_t* sizeWrapless)
- {
- int64_t tail = (cb->head + cb->count) % cb->bufSize;
-
- if ((cb->head + cb->count) < cb->bufSize)
- {
- *((void **) handle) = &cb->buffer[tail];
- *sizeWrapless = (cb->bufSize -(cb->head + cb->count));
- }
- else
- {
- *((void **) handle) = &cb->buffer[tail];
- *sizeWrapless = (cb->bufSize - cb->count);
- }
- }
- /* Please clone this sucker from readFromCircleBuffer */
- int accessCircleBuffer(CircleBuffer_t* cb, void* handle1, size_t requestSize)
- {
- int64_t head = cb->head;
- int64_t tail = (cb->head + cb->count) % cb->bufSize;
- void** handle = (void **) handle1;
- void* dest = *handle;
-
- if (requestSize <= 0)
- {
- return requestSize;
- }
- if (cb->count < requestSize)
- {
- return -1;
- }
-
-
- if (tail > head) /* the data does not wrap ! */
- {
- *handle = &cb->buffer[head];
- }
- else /* the current data does wrap */
- {
- /* but our read does not wrap */
- if (head + requestSize < cb->bufSize)
- {
- *handle = &cb->buffer[head];
- }
- else if (head + requestSize == cb->bufSize)
- {
- *handle = &cb->buffer[head];
- }
- else /* our read will wrap ! */
- {
- int64_t temp = cb->bufSize - head;
- dest = cb->maxChunk;
-
- assert(cb->maxChunkLen >= requestSize);
-
- circleread_memcpy(
- dest,
- &cb->buffer[head],
- temp);
- circleread_memcpy(
- ((unsigned char *) dest) + temp,
- cb->buffer,
- requestSize - temp);
- *handle = dest;
- }
- }
-
- cb->head = (cb->head + requestSize) % cb->bufSize;
- cb->count -= requestSize;
- cb->bytesConsumed += requestSize;
- cb->balance -= 1;
-
- return requestSize; /* records (16 bit or maybe other in future) */
- }
- /* return count read , or -1 if not enough data */
- /*----------------------------------------------*/
- int readFromCircleBuffer(CircleBuffer_t* cb, void* dest, size_t requestSize)
- {
- int64_t head = cb->head;
- int64_t tail = (cb->head + cb->count) % cb->bufSize;
-
- if (cb->count < requestSize)
- {
- requestSize = cb->count; /* Give them what we have */
- }
-
- if (requestSize <= 0)
- {
- return (int)requestSize;
- }
-
- if (tail > head) /* the data does not wrap ! */
- {
- circleread_memcpy(dest, &cb->buffer[head], requestSize);
- }
- else /* the current data does wrap */
- {
- /* but our read does not wrap */
- if (head + requestSize < cb->bufSize)
- {
- circleread_memcpy(dest, &cb->buffer[head], requestSize);
- }
- else if (head + requestSize == cb->bufSize)
- {
- circleread_memcpy(dest, &cb->buffer[head], requestSize);
- memset(&cb->buffer[head], 0, (size_t)requestSize); /* optional, debug */
- }
- else /* our read will wrap ! */
- {
- int64_t temp = cb->bufSize - head;
- circleread_memcpy(
- dest,
- &cb->buffer[head],
- temp);
- circleread_memcpy(
- ((unsigned char *) dest) + temp,
- cb->buffer,
- requestSize - temp);
- }
- }
-
- cb->head = (cb->head + requestSize) % cb->bufSize;
- cb->count -= requestSize;
- cb->bytesConsumed += requestSize;
- cb->balance -= 1;
-
- return (int)requestSize; /* records (16 bit or maybe other in future) */
- }
- void testCircleBuffer()
- {
- CircleBuffer_t temp;
- size_t bufSize = 256;
- const size_t maxInput = 256*3;
- size_t count = 0;
- size_t t;
- int i;
- const int maxRandom = 32;
- size_t chunkOut = 30;
-
- CircleRecord_t data[256*3];
-
- initCircleBuffer(&temp, bufSize, 75, 256, 0, 0);
-
- /* who cares ... take the default seed value. */
- while (count < maxInput || temp.count > chunkOut)
- {
- t = rand();
-
- /* for whatever reason this seems to be a 16 bit random number */
- t = t / ( 2 << (16 - 7) ) ;
-
- for(i = 0; i < (int)t; i++)
- {
- data[i] = (unsigned char ) ( count + i );
- }
-
- if (
- ((temp.bufSize - temp.count) >= t*sizeof(short)+1) &&
- (count < (maxInput - maxRandom))
- ) /* add 1 to keep buffer being completely filled */
- {
- int64_t tail = (temp.head + temp.count) % temp.bufSize;
- addToCircleBuffer(&temp, data, t);
- printf("Add to buffer count = %ld. head = %ld, tail = %ld\n", t, temp.head, tail);
- count += t;
- }
- else /* not enough space in buffer, try to empty some out */
- {
- int r;
- r = readFromCircleBuffer(&temp, data, chunkOut);
-
- if (r >= 0)
- {
- int64_t tail = (temp.head + temp.count) % temp.bufSize;
- for(i = 0; i < r; i++)
- printf("%ld ", data[i]);
- printf("\nRead from buffer. head = %ld, tail = %ld\n", temp.head, tail);
- }
- }
-
-
- } /* while we have not accumulated a large eough test ... */
-
- }
- int CirclePercent(CircleBuffer_t* cb)
- {
- return (int)(cb->count * 100 / cb->bufSize);
- }
- int CircleAtLevel(CircleBuffer_t* cb)
- {
- return (int)(cb->count * 100 / cb->bufSize) >= cb->percent;
- }
- int CircleOverLevel(CircleBuffer_t* cb)
- {
- return (int)(cb->count * 100 / cb->bufSize) > cb->percent;
- }
|