diff --git a/cpp_impl/CMakeLists.txt b/cpp_impl/CMakeLists.txt index 196674a..8923206 100644 --- a/cpp_impl/CMakeLists.txt +++ b/cpp_impl/CMakeLists.txt @@ -26,11 +26,17 @@ target_compile_features(UDPConnection PUBLIC cxx_std_11) 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) diff --git a/cpp_impl/src/TSQueue.cpp b/cpp_impl/src/TSQueue.cpp index b2f7f33..39c342e 100644 --- a/cpp_impl/src/TSQueue.cpp +++ b/cpp_impl/src/TSQueue.cpp @@ -3,17 +3,19 @@ #include 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(new unsigned char[this->capacity]); + std::unique_ptr(new unsigned char[this->capacityBytes]); } TSQueue::~TSQueue() {} @@ -27,7 +29,7 @@ bool TSQueue::push(void *data) { } memcpy(buffer.get() + tail, data, elemSize); - tail = (tail + elemSize) % capacity; + tail = (tail + elemSize) % capacityBytes; isEmpty = false; @@ -44,11 +46,7 @@ std::unique_ptr TSQueue::top() { } auto data = std::unique_ptr(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; } @@ -61,7 +59,7 @@ bool TSQueue::pop() { return false; } head += elemSize; - if (head >= capacity) { + if (head >= capacityBytes) { head = 0; } if (head == tail) { @@ -89,14 +87,14 @@ void TSQueue::changeCapacity(unsigned int newCapacity) { 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; @@ -107,15 +105,15 @@ void TSQueue::changeCapacity(unsigned int newCapacity) { 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); } } @@ -126,7 +124,7 @@ void TSQueue::changeCapacity(unsigned int newCapacity) { tail = tail - head; head = 0; } else { - tail = capacity - head + tail; + tail = capacityBytes - head + tail; head = 0; } } else { @@ -135,7 +133,7 @@ void TSQueue::changeCapacity(unsigned int newCapacity) { isEmpty = false; } buffer = std::move(newBuffer); - capacity = newCap; + capacityBytes = newCap; spinLock.store(false); } @@ -151,11 +149,34 @@ unsigned int TSQueue::size() { 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; + } + 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 = capacityBytes - head + tail; } spinLock.store(false); diff --git a/cpp_impl/src/TSQueue.hpp b/cpp_impl/src/TSQueue.hpp index 257f2c3..1afae60 100644 --- a/cpp_impl/src/TSQueue.hpp +++ b/cpp_impl/src/TSQueue.hpp @@ -29,12 +29,14 @@ class TSQueue { private: unsigned int elemSize; - unsigned int capacity; + unsigned int capacityBytes; unsigned int head; unsigned int tail; bool isEmpty; std::unique_ptr buffer; std::atomic_bool spinLock; + + unsigned int sizeBytes(); }; #endif diff --git a/cpp_impl/src/test/TestTSQueue.cpp b/cpp_impl/src/test/TestTSQueue.cpp new file mode 100644 index 0000000..698a0da --- /dev/null +++ b/cpp_impl/src/test/TestTSQueue.cpp @@ -0,0 +1,109 @@ +#include + +#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()); +} diff --git a/cpp_impl/src/test/UDPC_UnitTest.cpp b/cpp_impl/src/test/UDPC_UnitTest.cpp index b2f9976..5ebbc76 100644 --- a/cpp_impl/src/test/UDPC_UnitTest.cpp +++ b/cpp_impl/src/test/UDPC_UnitTest.cpp @@ -1,2 +1,6 @@ -int main() { +#include + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); }