From 381bbf9a7b97f4b2f5d947c74108a03ebc6ecd41 Mon Sep 17 00:00:00 2001
From: armatusmiles <akurotych@gmail.com>
Date: Thu, 24 Jan 2019 18:08:59 +0700
Subject: [PATCH] [+] dap_circular_buffer

---
 core/dap_circular_buffer.c    | 241 ++++++++++++++++++++++++++++++++++
 core/dap_circular_buffer.h    |  47 +++++++
 test/core/dap_circular_test.c |   8 ++
 test/core/dap_circular_test.h |   5 +
 test/core/main.c              |   2 +
 5 files changed, 303 insertions(+)
 create mode 100755 core/dap_circular_buffer.c
 create mode 100755 core/dap_circular_buffer.h
 create mode 100644 test/core/dap_circular_test.c
 create mode 100644 test/core/dap_circular_test.h

diff --git a/core/dap_circular_buffer.c b/core/dap_circular_buffer.c
new file mode 100755
index 0000000..ff75688
--- /dev/null
+++ b/core/dap_circular_buffer.c
@@ -0,0 +1,241 @@
+//
+//  CircularBuffer.c
+//
+//  Created by 罗亮富(Roen zxllf23@163.com) on 14-1-14.
+//  Copyright (c) 2014å¹´ All rights reserved.
+//
+
+
+#include "dap_circular_buffer.h"
+#include <string.h>
+
+struct s_circularBuffer{
+
+    size_t size; //capacity bytes size
+    size_t dataSize; //occupied data size
+    size_t tailOffset; //head offset, the oldest byte position offset
+    size_t headOffset; //tail offset, the lastest byte position offset
+    void *buffer;
+
+};
+
+extern CircularBuffer CircularBufferCreate(size_t size)
+{
+    size_t totalSize = sizeof(struct s_circularBuffer) + size;
+    void *p = malloc(totalSize);
+    CircularBuffer buffer = (CircularBuffer)p;
+    buffer->buffer = p + sizeof(struct s_circularBuffer);
+    buffer->size = size;
+    CircularBufferReset(buffer);
+    return buffer;
+}
+
+void CircularBufferFree(CircularBuffer cBuf)
+{
+    CircularBufferReset(cBuf);
+    cBuf->size = 0;
+    cBuf->dataSize = 0;
+    cBuf->buffer = NULL;
+    free(cBuf);
+}
+
+void CircularBufferReset(CircularBuffer cBuf)
+{
+    cBuf->headOffset = -1;
+    cBuf->tailOffset = -1;
+    cBuf->dataSize = 0;
+}
+
+size_t CircularBufferGetSize(CircularBuffer cBuf)
+{
+    return cBuf->size;
+}
+
+size_t CircularBufferGetDataSize(CircularBuffer cBuf)
+{
+    return cBuf->dataSize;
+}
+
+void CircularBufferPush(CircularBuffer cBuf,void *src, size_t length)
+{
+    size_t writableLen = length;
+    void *pSrc = src;
+
+    if(writableLen > cBuf->size)//in case of size overflow
+    {
+        size_t overFlowLen = writableLen - cBuf->size;
+        writableLen = cBuf->size;
+        pSrc = src + overFlowLen;
+    }
+
+
+    bool resetHead = false;
+    //in case the circle buffer won't be full after adding the data
+    if(cBuf->tailOffset+writableLen < cBuf->size)
+    {
+        memcpy(&cBuf->buffer[cBuf->tailOffset + 1], pSrc, writableLen);
+
+        if((cBuf->tailOffset < cBuf->headOffset) && (cBuf->tailOffset+writableLen >= cBuf->headOffset) )
+            resetHead = true;
+
+        cBuf->tailOffset += writableLen;
+    }
+    else//in case the circle buffer will be overflow after adding the data
+    {
+        size_t remainSize = cBuf->size - cBuf->tailOffset - 1; //the remain size
+        memcpy(&cBuf->buffer[cBuf->tailOffset+1], pSrc, remainSize);
+
+        size_t coverSize = writableLen - remainSize; //size of data to be covered from the beginning
+        memcpy(cBuf->buffer, pSrc+remainSize, coverSize);
+
+        if(cBuf->tailOffset < cBuf->headOffset)
+            resetHead = true;
+        else
+        {
+            if(coverSize>cBuf->headOffset)
+                resetHead = true;
+        }
+
+        cBuf->tailOffset = coverSize - 1;
+    }
+
+    if(cBuf->headOffset == -1)
+        cBuf->headOffset = 0;
+
+    if(resetHead)
+    {
+        if(cBuf->tailOffset+1 < cBuf->size)
+            cBuf->headOffset = cBuf->tailOffset + 1;
+        else
+            cBuf->headOffset = 0;
+
+        cBuf->dataSize = cBuf->size;
+    }
+    else
+    {
+        if(cBuf->tailOffset >= cBuf->headOffset)
+            cBuf->dataSize = cBuf->tailOffset - cBuf->headOffset + 1;
+        else
+            cBuf->dataSize = cBuf->size - (cBuf->headOffset - cBuf->tailOffset - 1);
+    }
+}
+
+size_t inter_circularBuffer_read(CircularBuffer cBuf, size_t length, void *dataOut, bool resetHead)
+{
+    if(cBuf->dataSize == 0 || length == 0)
+        return 0;
+
+    size_t rdLen = length;
+
+    if(cBuf->dataSize < rdLen)
+        rdLen = cBuf->dataSize;
+
+
+    if(cBuf->headOffset <= cBuf->tailOffset)
+    {
+        if(dataOut)
+            memcpy(dataOut, &cBuf->buffer[cBuf->headOffset], rdLen);
+
+        if(resetHead)
+        {
+            cBuf->headOffset += rdLen;
+            if(cBuf->headOffset > cBuf->tailOffset)
+            {
+                cBuf->headOffset = -1;
+                cBuf->tailOffset = -1;
+            }
+        }
+    }
+    else
+    {
+        if(cBuf->headOffset+rdLen <= cBuf->size)
+        {
+            if(dataOut)
+                memcpy(dataOut, &cBuf->buffer[cBuf->headOffset], rdLen);
+
+            if(resetHead)
+            {
+                cBuf->headOffset += rdLen;
+                if(cBuf->headOffset == cBuf->size)
+                    cBuf->headOffset = 0;
+            }
+        }
+        else
+        {
+            size_t frg1Len = cBuf->size - cBuf->headOffset;
+            if(dataOut)
+                memcpy(dataOut, &cBuf->buffer[cBuf->headOffset], frg1Len);
+
+            size_t frg2len = rdLen - frg1Len;
+            if(dataOut)
+                memcpy(dataOut+frg1Len, cBuf->buffer, frg2len);
+
+            if(resetHead)
+            {
+                cBuf->headOffset = frg2len;
+                if(cBuf->headOffset > cBuf->tailOffset)
+                {
+                    cBuf->headOffset = -1;
+                    cBuf->tailOffset = -1;
+                }
+            }
+        }
+    }
+
+    if(resetHead)
+        cBuf->dataSize -= rdLen;
+
+    return rdLen;
+}
+
+
+size_t CircularBufferPop(CircularBuffer cBuf, size_t length, void *dataOut)
+{
+    return inter_circularBuffer_read(cBuf,length,dataOut,true);
+}
+
+size_t CircularBufferRead(CircularBuffer cBuf, size_t length, void *dataOut)
+{
+    return inter_circularBuffer_read(cBuf,length,dataOut,false);
+}
+
+
+//print circular buffer's content into str,
+void CircularBufferPrint(CircularBuffer cBuf, bool hex)
+{
+    char *b = cBuf->buffer;
+    size_t cSize = CircularBufferGetSize(cBuf);
+    char *str = malloc(2*cSize+1);
+
+    char c;
+
+    for(size_t i=0; i<cSize; i++)
+    {
+        if(CircularBufferGetDataSize(cBuf) == 0)
+        {
+            c = '_';
+        }
+        else if (cBuf->tailOffset < cBuf->headOffset)
+        {
+            if(i>cBuf->tailOffset && i<cBuf->headOffset)
+                c = '_';
+            else
+              c = b[i];
+        }
+        else
+        {
+            if(i>cBuf->tailOffset || i<cBuf->headOffset)
+                c = '_';
+            else
+                c = b[i];
+        }
+        if(hex)
+            sprintf(str+i*2, "%02X|",c);
+        else
+            sprintf(str+i*2, "%c|",c);
+    }
+
+    printf("CircularBuffer: %s <size %zu dataSize:%zu>\n",str,CircularBufferGetSize(cBuf),CircularBufferGetDataSize(cBuf));
+
+    free(str);
+}
diff --git a/core/dap_circular_buffer.h b/core/dap_circular_buffer.h
new file mode 100755
index 0000000..459402b
--- /dev/null
+++ b/core/dap_circular_buffer.h
@@ -0,0 +1,47 @@
+//
+//  CircularBuffer.h
+//
+//  Created by 罗亮富(Roen)zxllf23@163.com on 14-1-14.
+//  Copyright (c) 2014å¹´ All rights reserved.
+//
+
+#ifndef YYDJ_Roen_CircularBuffer_h
+#define YYDJ_Roen_CircularBuffer_h
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+/*
+ A circular buffer(circular queue, cyclic buffer or ring buffer), is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams. visit https://en.wikipedia.org/wiki/Circular_buffer to see more information.
+ */
+
+typedef struct s_circularBuffer* CircularBuffer;
+
+// Construct CircularBuffer with ‘size' in byte. You must call CircularBufferFree() in balance for destruction.
+extern CircularBuffer CircularBufferCreate(size_t size);
+
+// Destruct CircularBuffer
+extern void CircularBufferFree(CircularBuffer cBuf);
+
+// Reset the CircularBuffer
+extern void CircularBufferReset(CircularBuffer cBuf);
+
+//get the capacity of CircularBuffer
+extern size_t CircularBufferGetSize(CircularBuffer cBuf);
+
+//get occupied data size of CircularBuffer
+extern size_t CircularBufferGetDataSize(CircularBuffer cBuf);
+
+// Push data to the tail of a circular buffer from 'src' with 'length' size in byte.
+extern void CircularBufferPush(CircularBuffer cBuf,void *src, size_t length);
+
+// Pop data from a circular buffer to 'dataOut'  with wished 'length' size in byte,return the actual data size in byte popped out,which is less or equal to the input 'length parameter.
+extern size_t CircularBufferPop(CircularBuffer cBuf, size_t length, void *dataOut);
+
+// Read data from a circular buffer to 'dataOut'  with wished 'length' size in byte,return the actual data size in byte popped out,which is less or equal to the input 'length parameter.
+extern size_t CircularBufferRead(CircularBuffer cBuf, size_t length, void *dataOut);
+
+//for test purpose, print the circular buffer's data content by printf(...); the 'hex' parameters indicates that if the data should be printed in asscii string or hex data format.
+extern void CircularBufferPrint(CircularBuffer cBuf, bool hex);
+
+#endif
diff --git a/test/core/dap_circular_test.c b/test/core/dap_circular_test.c
new file mode 100644
index 0000000..af021e4
--- /dev/null
+++ b/test/core/dap_circular_test.c
@@ -0,0 +1,8 @@
+#include "dap_circular_test.h"
+#include "dap_circular_buffer.h"
+
+
+void dap_circular_test_run()
+{
+    dap_print_module_name("dap_circular");
+}
diff --git a/test/core/dap_circular_test.h b/test/core/dap_circular_test.h
new file mode 100644
index 0000000..51a73ae
--- /dev/null
+++ b/test/core/dap_circular_test.h
@@ -0,0 +1,5 @@
+#pragma once
+#include "dap_test.h"
+#include "dap_common.h"
+
+extern void dap_circular_test_run(void);
diff --git a/test/core/main.c b/test/core/main.c
index 53ec99e..cd9355a 100755
--- a/test/core/main.c
+++ b/test/core/main.c
@@ -1,12 +1,14 @@
 #include "dap_config_test.h"
 #include "dap_common_test.h"
 #include "dap_network_monitor_test.h"
+#include "dap_circular_test.h"
 #include "dap_common.h"
 
 
 int main(void) {
     // switch off debug info from library
     set_log_level(L_CRITICAL);
+    dap_circular_test_run();
     dap_config_tests_run();
     dap_common_test_run();
 #ifdef __linux__
-- 
GitLab