added ring buffer class
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 6 Jul 2017 19:32:33 +0000 (22:32 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 6 Jul 2017 19:32:33 +0000 (22:32 +0300)
include/nms_util.h
src/libnetxms/Makefile.am
src/libnetxms/Makefile.w32
src/libnetxms/bytestream.cpp
src/libnetxms/rbuffer.cpp [new file with mode: 0644]
tests/test-libnetxms/test-libnetxms.cpp

index 037c0d0..a5b0252 100644 (file)
@@ -1139,6 +1139,29 @@ public:
 };
 
 /**
+ * Ring buffer
+ */
+class LIBNETXMS_EXPORTABLE RingBuffer
+{
+private:
+   BYTE *m_data;
+   size_t m_size;
+   size_t m_allocated;
+   size_t m_allocationStep;
+   size_t m_readPos;
+   size_t m_writePos;
+
+public:
+   RingBuffer(size_t initial = 8192, size_t allocationStep = 8192);
+   ~RingBuffer();
+
+   void write(const BYTE *data, size_t dataSize);
+   size_t read(BYTE *buffer, size_t bufferSize);
+
+   size_t size() const { return m_size; }
+};
+
+/**
  * Byte stream
  */
 class LIBNETXMS_EXPORTABLE ByteStream
index 73ff8c7..f058d6f 100644 (file)
@@ -4,11 +4,11 @@ SOURCES = array.cpp base64.cpp bytestream.cpp cc_mb.cpp cc_ucs2.cpp \
          hashmapbase.cpp ice.c icmp.cpp icmp6.cpp iconv.cpp inet_pton.c \
          inetaddr.cpp log.cpp lz4.c main.cpp md5.cpp message.cpp \
          msgrecv.cpp msgwq.cpp net.cpp nxcp.cpp pa.cpp parisc_atomic.cpp \
-          qsort.c queue.cpp rwlock.cpp scandir.c serial.cpp sha1.cpp sha2.cpp \
-          solaris9_atomic.c spoll.cpp streamcomp.cpp string.cpp \
-         stringlist.cpp strmap.cpp strmapbase.cpp strptime.c strset.cpp \
-         strtoll.c strtoull.c table.cpp threads.cpp timegm.c tools.cpp \
-         tp.cpp unicode.cpp uuid.cpp wcstoll.c wcstoull.c xml.cpp \
+          qsort.c queue.cpp rbuffer.cpp rwlock.cpp scandir.c serial.cpp \
+         sha1.cpp sha2.cpp solaris9_atomic.c spoll.cpp streamcomp.cpp \
+         string.cpp stringlist.cpp strmap.cpp strmapbase.cpp strptime.c \
+         strset.cpp strtoll.c strtoull.c table.cpp threads.cpp timegm.c \
+         tools.cpp tp.cpp unicode.cpp uuid.cpp wcstoll.c wcstoull.c xml.cpp \
          wcscasecmp.cpp wcsncasecmp.cpp
 
 lib_LTLIBRARIES = libnetxms.la
index 9f690cd..be9dca8 100644 (file)
@@ -6,7 +6,8 @@ SOURCES = array.cpp base64.cpp bytestream.cpp cc_mb.cpp cc_ucs2.cpp \
        hashmapbase.cpp ice.c icmp.cpp \
        inetaddr.cpp log.cpp lz4.c main.cpp md5.cpp message.cpp \
        msgrecv.cpp msgwq.cpp net.cpp nxcp.cpp pa.cpp \
-       qsort.c queue.cpp rwlock.cpp scandir.c seh.cpp serial.cpp sha1.cpp sha2.cpp \
+       qsort.c queue.cpp rbuffer.cpp rwlock.cpp scandir.c seh.cpp \
+       serial.cpp sha1.cpp sha2.cpp \
        spoll.cpp StackWalker.cpp streamcomp.cpp string.cpp \
        stringlist.cpp strmap.cpp strmapbase.cpp strptime.c strset.cpp \
        strtoll.c strtoull.c table.cpp threads.cpp timegm.c tools.cpp \
index 53526fd..328d059 100644 (file)
@@ -1,7 +1,7 @@
 /*
  ** NetXMS - Network Management System
  ** NetXMS Foundation Library
- ** Copyright (C) 2003-2015 Raden Solutions
+ ** Copyright (C) 2003-2017 Raden Solutions
  **
  ** This program is free software; you can redistribute it and/or modify
  ** it under the terms of the GNU Lesser General Public License as published
@@ -17,7 +17,7 @@
  ** along with this program; if not, write to the Free Software
  ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  **
- ** File: config.cpp
+ ** File: bytestream.cpp
  **
  **/
 
diff --git a/src/libnetxms/rbuffer.cpp b/src/libnetxms/rbuffer.cpp
new file mode 100644 (file)
index 0000000..de3d45a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ ** NetXMS - Network Management System
+ ** NetXMS Foundation Library
+ ** Copyright (C) 2003-2017 Raden Solutions
+ **
+ ** This program is free software; you can redistribute it and/or modify
+ ** it under the terms of the GNU Lesser General Public License as published
+ ** by the Free Software Foundation; either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU Lesser General Public License
+ ** along with this program; if not, write to the Free Software
+ ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ **
+ ** File: rbuffer.cpp
+ **
+ **/
+
+#include "libnetxms.h"
+
+/**
+ * Constructor
+ */
+RingBuffer::RingBuffer(size_t initial, size_t allocationStep)
+{
+   m_data = (BYTE *)malloc(initial);
+   m_size = 0;
+   m_allocated = initial;
+   m_allocationStep = allocationStep;
+   m_readPos = 0;
+   m_writePos = 0;
+}
+
+/**
+ * Destructor
+ */
+RingBuffer::~RingBuffer()
+{
+   free(m_data);
+}
+
+/**
+ * Write data
+ */
+void RingBuffer::write(const BYTE *data, size_t dataSize)
+{
+   if (dataSize <= m_allocated - m_size)
+   {
+      size_t chunkSize = m_allocated - m_writePos;
+      if (dataSize <= chunkSize)
+      {
+         memcpy(&m_data[m_writePos], data, dataSize);
+         m_writePos += dataSize;
+      }
+      else
+      {
+         memcpy(&m_data[m_writePos], data, chunkSize);
+         memcpy(m_data, &data[chunkSize], dataSize - chunkSize);
+         m_writePos = dataSize - chunkSize;
+      }
+   }
+   else if (m_writePos > m_readPos)
+   {
+      m_allocated += max(dataSize, m_allocationStep);
+      m_data = (BYTE *)realloc(m_data, m_allocated);
+      memcpy(&m_data[m_writePos], data, dataSize);
+      m_writePos += dataSize;
+   }
+   else
+   {
+      size_t tailSize = m_allocated - m_readPos;
+      m_allocated = m_size + dataSize + m_allocationStep;
+      BYTE *temp = (BYTE *)malloc(m_allocated);
+      memcpy(temp, &m_data[m_readPos], tailSize);
+      memcpy(&temp[tailSize], m_data, m_writePos);
+      memcpy(&temp[m_size], data, dataSize);
+      free(m_data);
+      m_data = temp;
+      m_readPos = 0;
+      m_writePos = m_size + dataSize;
+   }
+   m_size += dataSize;
+}
+
+/**
+ * Read data
+ */
+size_t RingBuffer::read(BYTE *buffer, size_t bufferSize)
+{
+   size_t readSize = min(bufferSize, m_size);
+   if (readSize == 0)
+      return 0;
+
+   if (m_readPos + readSize > m_allocated)
+   {
+      size_t chunkSize = m_allocated - m_readPos;
+      memcpy(buffer, &m_data[m_readPos], chunkSize);
+      memcpy(&buffer[chunkSize], m_data, readSize - chunkSize);
+      m_readPos = chunkSize;
+   }
+   else
+   {
+      memcpy(buffer, &m_data[m_readPos], readSize);
+      m_readPos += readSize;
+   }
+
+   m_size -= readSize;
+   return readSize;
+}
index 0be002c..4214108 100644 (file)
@@ -732,6 +732,79 @@ static void TestDiff()
 }
 
 /**
+ * Test ring buffer
+ */
+static void TestRingBuffer()
+{
+   RingBuffer rb(32, 32);
+   char buffer[256];
+
+   StartTest(_T("RingBuffer: write #1"));
+   rb.write((const BYTE *)"short data", 10);
+   AssertEquals(rb.size(), 10);
+   EndTest();
+
+   StartTest(_T("RingBuffer: read #1"));
+   size_t bytes = rb.read((BYTE *)buffer, 256);
+   AssertEquals(bytes, 10);
+   AssertTrue(!memcmp(buffer, "short data", 10));
+   AssertEquals(rb.size(), 0);
+   EndTest();
+
+   StartTest(_T("RingBuffer: write #2"));
+   rb.write((const BYTE *)"short data", 10);
+   AssertEquals(rb.size(), 10);
+   EndTest();
+
+   StartTest(_T("RingBuffer: read #2"));
+   memset(buffer, 0, 256);
+   bytes = rb.read((BYTE *)buffer, 4);
+   AssertEquals(bytes, 4);
+   AssertTrue(!memcmp(buffer, "shor", 4));
+   AssertEquals(rb.size(), 6);
+   EndTest();
+
+   StartTest(_T("RingBuffer: write #3"));
+   rb.write((const BYTE *)"long data: 123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.", 111);
+   AssertEquals(rb.size(), 117);
+   EndTest();
+
+   StartTest(_T("RingBuffer: read #3"));
+   memset(buffer, 0, 256);
+   bytes = rb.read((BYTE *)buffer, 17);
+   AssertEquals(bytes, 17);
+   AssertTrue(!memcmp(buffer, "t datalong data: ", 17));
+   AssertEquals(rb.size(), 100);
+   EndTest();
+
+   StartTest(_T("RingBuffer: write #4"));
+   rb.write((const BYTE *)"short data", 10);
+   AssertEquals(rb.size(), 110);
+   EndTest();
+
+   StartTest(_T("RingBuffer: read #4"));
+   memset(buffer, 0, 256);
+   bytes = rb.read((BYTE *)buffer, 108);
+   AssertEquals(bytes, 108);
+   AssertTrue(!memcmp(buffer, "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.short da", 108));
+   AssertEquals(rb.size(), 2);
+   EndTest();
+
+   StartTest(_T("RingBuffer: write #5"));
+   rb.write((const BYTE *)"test", 4);
+   AssertEquals(rb.size(), 6);
+   EndTest();
+
+   StartTest(_T("RingBuffer: read #5"));
+   memset(buffer, 0, 256);
+   bytes = rb.read((BYTE *)buffer, 256);
+   AssertEquals(bytes, 6);
+   AssertTrue(!memcmp(buffer, "tatest", 6));
+   AssertEquals(rb.size(), 0);
+   EndTest();
+}
+
+/**
  * main()
  */
 int main(int argc, char *argv[])
@@ -758,6 +831,7 @@ int main(int argc, char *argv[])
    TestConditionWrapper();
    TestByteSwap();
    TestDiff();
+   TestRingBuffer();
 
    MsgWaitQueue::shutdown();
    return 0;