target_link_libraries(UDPConnection PUBLIC pthread)
if(CMAKE_BUILD_TYPE MATCHES "Debug")
- set(UDPC_UnitTest_SOURCES
- src/test/UDPC_UnitTest.cpp)
- add_executable(UnitTest ${UDPC_UnitTest_SOURCES})
- target_link_libraries(UnitTest PUBLIC UDPConnection)
- target_include_directories(UnitTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+ find_package(GTest QUIET)
+ if(GTEST_FOUND)
+ set(UDPC_UnitTest_SOURCES
+ src/test/UDPC_UnitTest.cpp
+ src/test/TestTSQueue.cpp
+ )
+ add_executable(UnitTest ${UDPC_UnitTest_SOURCES})
+ target_link_libraries(UnitTest PUBLIC UDPConnection ${GTEST_BOTH_LIBRARIES})
+ target_include_directories(UnitTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
+ endif()
set(UDPC_NetworkTest_SOURCES
src/test/UDPC_NetworkTest.cpp)
#include <cstring>
TSQueue::TSQueue(unsigned int elemSize, unsigned int capacity)
- : elemSize(elemSize), capacity(capacity), head(0), tail(0), isEmpty(true),
+ : elemSize(elemSize), head(0), tail(0), isEmpty(true),
spinLock(false) {
if (elemSize == 0) {
this->elemSize = 1;
}
if (capacity == 0) {
- this->capacity = UDPC_TSQUEUE_DEFAULT_CAPACITY * this->elemSize;
+ this->capacityBytes = UDPC_TSQUEUE_DEFAULT_CAPACITY * this->elemSize;
+ } else {
+ this->capacityBytes = capacity * this->elemSize;
}
this->buffer =
- std::unique_ptr<unsigned char[]>(new unsigned char[this->capacity]);
+ std::unique_ptr<unsigned char[]>(new unsigned char[this->capacityBytes]);
}
TSQueue::~TSQueue() {}
}
memcpy(buffer.get() + tail, data, elemSize);
- tail = (tail + elemSize) % capacity;
+ tail = (tail + elemSize) % capacityBytes;
isEmpty = false;
}
auto data = std::unique_ptr<unsigned char[]>(new unsigned char[elemSize]);
- if (tail != 0) {
- memcpy(data.get(), buffer.get() + (tail - elemSize), elemSize);
- } else {
- memcpy(data.get(), buffer.get() + (capacity - elemSize), elemSize);
- }
+ memcpy(data.get(), buffer.get() + head, elemSize);
spinLock.store(false);
return data;
}
return false;
}
head += elemSize;
- if (head >= capacity) {
+ if (head >= capacityBytes) {
head = 0;
}
if (head == tail) {
while (spinLock.exchange(true) == true) {
}
- // repeat of size() to avoid deadlock
+ // repeat of sizeBytes() to avoid deadlock
unsigned int size;
if (head == tail) {
- size = capacity;
+ size = capacityBytes;
} else if (head < tail) {
size = tail - head;
} else {
- size = capacity - head + tail;
+ size = capacityBytes - head + tail;
}
unsigned int newCap = newCapacity * elemSize;
unsigned int tempHead = head;
if (size > newCap) {
unsigned int diff = size - newCap;
- tempHead = (head + diff) % capacity;
+ tempHead = (head + diff) % capacityBytes;
}
if (tempHead < tail) {
memcpy(newBuffer.get(), buffer.get() + tempHead, tail - tempHead);
} else {
memcpy(newBuffer.get(), buffer.get() + tempHead,
- capacity - tempHead);
+ capacityBytes - tempHead);
if (tail != 0) {
- memcpy(newBuffer.get() + capacity - tempHead, buffer.get(),
+ memcpy(newBuffer.get() + capacityBytes - tempHead, buffer.get(),
tail);
}
}
tail = tail - head;
head = 0;
} else {
- tail = capacity - head + tail;
+ tail = capacityBytes - head + tail;
head = 0;
}
} else {
isEmpty = false;
}
buffer = std::move(newBuffer);
- capacity = newCap;
+ capacityBytes = newCap;
spinLock.store(false);
}
unsigned int size;
if (head == tail) {
- size = capacity;
+ size = capacityBytes;
+ } else if (head < tail) {
+ size = tail - head;
+ } else {
+ size = capacityBytes - head + tail;
+ }
+ size /= elemSize;
+
+ spinLock.store(false);
+ return size;
+}
+
+unsigned int TSQueue::sizeBytes() {
+ while (spinLock.exchange(true) == true) {
+ }
+
+ if (isEmpty) {
+ spinLock.store(false);
+ return 0;
+ }
+
+ unsigned int size;
+ if (head == tail) {
+ size = capacityBytes;
} else if (head < tail) {
size = tail - head;
} else {
- size = capacity - head + tail;
+ size = capacityBytes - head + tail;
}
spinLock.store(false);
private:
unsigned int elemSize;
- unsigned int capacity;
+ unsigned int capacityBytes;
unsigned int head;
unsigned int tail;
bool isEmpty;
std::unique_ptr<unsigned char[]> buffer;
std::atomic_bool spinLock;
+
+ unsigned int sizeBytes();
};
#endif
--- /dev/null
+#include <gtest/gtest.h>
+
+#include "TSQueue.hpp"
+
+TEST(TSQueue, Usage)
+{
+ TSQueue q(sizeof(int), 4);
+ int temp = 100;
+
+ EXPECT_EQ(q.size(), 0);
+ EXPECT_FALSE(q.pop());
+
+ EXPECT_TRUE(q.push(&temp));
+ EXPECT_EQ(q.size(), 1);
+
+ // { 100 }
+
+ temp = 200;
+ EXPECT_TRUE(q.push(&temp));
+ EXPECT_EQ(q.size(), 2);
+ auto top = q.top();
+ EXPECT_EQ(100, *((int*)top.get()));
+
+ // { 100, 200 }
+
+ temp = 300;
+ EXPECT_TRUE(q.push(&temp));
+ EXPECT_EQ(q.size(), 3);
+
+ // { 100, 200, 300 }
+
+ temp = 400;
+ EXPECT_TRUE(q.push(&temp));
+ EXPECT_EQ(q.size(), 4);
+
+ // { 100, 200, 300, 400 }
+
+ temp = 500;
+ EXPECT_FALSE(q.push(&temp));
+ EXPECT_EQ(q.size(), 4);
+
+ top = q.top();
+ EXPECT_EQ(100, *((int*)top.get()));
+
+ EXPECT_TRUE(q.pop());
+ EXPECT_EQ(q.size(), 3);
+
+ // { 200, 300, 400 }
+
+ top = q.top();
+ EXPECT_EQ(200, *((int*)top.get()));
+
+ temp = 1;
+ EXPECT_TRUE(q.push(&temp));
+ EXPECT_EQ(q.size(), 4);
+
+ // { 200, 300, 400, 1 }
+
+ top = q.top();
+ EXPECT_EQ(200, *((int*)top.get()));
+
+ temp = 2;
+ EXPECT_FALSE(q.push(&temp));
+ EXPECT_EQ(q.size(), 4);
+
+ q.changeCapacity(8);
+ EXPECT_EQ(q.size(), 4);
+
+ temp = 10;
+ EXPECT_TRUE(q.push(&temp));
+ EXPECT_EQ(q.size(), 5);
+
+ // { 200, 300, 400, 1, 10 }
+
+ top = q.top();
+ EXPECT_EQ(200, *((int*)top.get()));
+
+ EXPECT_TRUE(q.pop());
+ EXPECT_EQ(q.size(), 4);
+
+ // { 300, 400, 1, 10 }
+
+ top = q.top();
+ EXPECT_EQ(300, *((int*)top.get()));
+
+ EXPECT_TRUE(q.pop());
+ EXPECT_EQ(q.size(), 3);
+
+ // { 400, 1, 10 }
+
+ top = q.top();
+ EXPECT_EQ(400, *((int*)top.get()));
+
+ q.changeCapacity(1);
+
+ // { 10 }
+
+ EXPECT_EQ(q.size(), 1);
+
+ top = q.top();
+ EXPECT_EQ(10, *((int*)top.get()));
+
+ EXPECT_TRUE(q.pop());
+
+ // { }
+
+ EXPECT_FALSE(q.pop());
+ EXPECT_EQ(0, q.size());
+}
-int main() {
+#include <gtest/gtest.h>
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}