Add unit test and fixes for TSQueue
This commit is contained in:
parent
76567d168e
commit
8548d4f6ed
5 changed files with 169 additions and 27 deletions
|
@ -26,11 +26,17 @@ target_compile_features(UDPConnection PUBLIC cxx_std_11)
|
||||||
target_link_libraries(UDPConnection PUBLIC pthread)
|
target_link_libraries(UDPConnection PUBLIC pthread)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
|
|
||||||
|
find_package(GTest QUIET)
|
||||||
|
if(GTEST_FOUND)
|
||||||
set(UDPC_UnitTest_SOURCES
|
set(UDPC_UnitTest_SOURCES
|
||||||
src/test/UDPC_UnitTest.cpp)
|
src/test/UDPC_UnitTest.cpp
|
||||||
|
src/test/TestTSQueue.cpp
|
||||||
|
)
|
||||||
add_executable(UnitTest ${UDPC_UnitTest_SOURCES})
|
add_executable(UnitTest ${UDPC_UnitTest_SOURCES})
|
||||||
target_link_libraries(UnitTest PUBLIC UDPConnection)
|
target_link_libraries(UnitTest PUBLIC UDPConnection ${GTEST_BOTH_LIBRARIES})
|
||||||
target_include_directories(UnitTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(UnitTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(UDPC_NetworkTest_SOURCES
|
set(UDPC_NetworkTest_SOURCES
|
||||||
src/test/UDPC_NetworkTest.cpp)
|
src/test/UDPC_NetworkTest.cpp)
|
||||||
|
|
|
@ -3,17 +3,19 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
TSQueue::TSQueue(unsigned int elemSize, unsigned int capacity)
|
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) {
|
spinLock(false) {
|
||||||
if (elemSize == 0) {
|
if (elemSize == 0) {
|
||||||
this->elemSize = 1;
|
this->elemSize = 1;
|
||||||
}
|
}
|
||||||
if (capacity == 0) {
|
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 =
|
this->buffer =
|
||||||
std::unique_ptr<unsigned char[]>(new unsigned char[this->capacity]);
|
std::unique_ptr<unsigned char[]>(new unsigned char[this->capacityBytes]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSQueue::~TSQueue() {}
|
TSQueue::~TSQueue() {}
|
||||||
|
@ -27,7 +29,7 @@ bool TSQueue::push(void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer.get() + tail, data, elemSize);
|
memcpy(buffer.get() + tail, data, elemSize);
|
||||||
tail = (tail + elemSize) % capacity;
|
tail = (tail + elemSize) % capacityBytes;
|
||||||
|
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
|
|
||||||
|
@ -44,11 +46,7 @@ std::unique_ptr<unsigned char[]> TSQueue::top() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = std::unique_ptr<unsigned char[]>(new unsigned char[elemSize]);
|
auto data = std::unique_ptr<unsigned char[]>(new unsigned char[elemSize]);
|
||||||
if (tail != 0) {
|
memcpy(data.get(), buffer.get() + head, elemSize);
|
||||||
memcpy(data.get(), buffer.get() + (tail - elemSize), elemSize);
|
|
||||||
} else {
|
|
||||||
memcpy(data.get(), buffer.get() + (capacity - elemSize), elemSize);
|
|
||||||
}
|
|
||||||
spinLock.store(false);
|
spinLock.store(false);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +59,7 @@ bool TSQueue::pop() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
head += elemSize;
|
head += elemSize;
|
||||||
if (head >= capacity) {
|
if (head >= capacityBytes) {
|
||||||
head = 0;
|
head = 0;
|
||||||
}
|
}
|
||||||
if (head == tail) {
|
if (head == tail) {
|
||||||
|
@ -89,14 +87,14 @@ void TSQueue::changeCapacity(unsigned int newCapacity) {
|
||||||
while (spinLock.exchange(true) == true) {
|
while (spinLock.exchange(true) == true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// repeat of size() to avoid deadlock
|
// repeat of sizeBytes() to avoid deadlock
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
if (head == tail) {
|
if (head == tail) {
|
||||||
size = capacity;
|
size = capacityBytes;
|
||||||
} else if (head < tail) {
|
} else if (head < tail) {
|
||||||
size = tail - head;
|
size = tail - head;
|
||||||
} else {
|
} else {
|
||||||
size = capacity - head + tail;
|
size = capacityBytes - head + tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int newCap = newCapacity * elemSize;
|
unsigned int newCap = newCapacity * elemSize;
|
||||||
|
@ -107,15 +105,15 @@ void TSQueue::changeCapacity(unsigned int newCapacity) {
|
||||||
unsigned int tempHead = head;
|
unsigned int tempHead = head;
|
||||||
if (size > newCap) {
|
if (size > newCap) {
|
||||||
unsigned int diff = size - newCap;
|
unsigned int diff = size - newCap;
|
||||||
tempHead = (head + diff) % capacity;
|
tempHead = (head + diff) % capacityBytes;
|
||||||
}
|
}
|
||||||
if (tempHead < tail) {
|
if (tempHead < tail) {
|
||||||
memcpy(newBuffer.get(), buffer.get() + tempHead, tail - tempHead);
|
memcpy(newBuffer.get(), buffer.get() + tempHead, tail - tempHead);
|
||||||
} else {
|
} else {
|
||||||
memcpy(newBuffer.get(), buffer.get() + tempHead,
|
memcpy(newBuffer.get(), buffer.get() + tempHead,
|
||||||
capacity - tempHead);
|
capacityBytes - tempHead);
|
||||||
if (tail != 0) {
|
if (tail != 0) {
|
||||||
memcpy(newBuffer.get() + capacity - tempHead, buffer.get(),
|
memcpy(newBuffer.get() + capacityBytes - tempHead, buffer.get(),
|
||||||
tail);
|
tail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +124,7 @@ void TSQueue::changeCapacity(unsigned int newCapacity) {
|
||||||
tail = tail - head;
|
tail = tail - head;
|
||||||
head = 0;
|
head = 0;
|
||||||
} else {
|
} else {
|
||||||
tail = capacity - head + tail;
|
tail = capacityBytes - head + tail;
|
||||||
head = 0;
|
head = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -135,7 +133,7 @@ void TSQueue::changeCapacity(unsigned int newCapacity) {
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
}
|
}
|
||||||
buffer = std::move(newBuffer);
|
buffer = std::move(newBuffer);
|
||||||
capacity = newCap;
|
capacityBytes = newCap;
|
||||||
|
|
||||||
spinLock.store(false);
|
spinLock.store(false);
|
||||||
}
|
}
|
||||||
|
@ -151,11 +149,34 @@ unsigned int TSQueue::size() {
|
||||||
|
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
if (head == tail) {
|
if (head == tail) {
|
||||||
size = capacity;
|
size = capacityBytes;
|
||||||
} else if (head < tail) {
|
} else if (head < tail) {
|
||||||
size = tail - head;
|
size = tail - head;
|
||||||
} else {
|
} 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);
|
spinLock.store(false);
|
||||||
|
|
|
@ -29,12 +29,14 @@ class TSQueue {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int elemSize;
|
unsigned int elemSize;
|
||||||
unsigned int capacity;
|
unsigned int capacityBytes;
|
||||||
unsigned int head;
|
unsigned int head;
|
||||||
unsigned int tail;
|
unsigned int tail;
|
||||||
bool isEmpty;
|
bool isEmpty;
|
||||||
std::unique_ptr<unsigned char[]> buffer;
|
std::unique_ptr<unsigned char[]> buffer;
|
||||||
std::atomic_bool spinLock;
|
std::atomic_bool spinLock;
|
||||||
|
|
||||||
|
unsigned int sizeBytes();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
109
cpp_impl/src/test/TestTSQueue.cpp
Normal file
109
cpp_impl/src/test/TestTSQueue.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#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());
|
||||||
|
}
|
|
@ -1,2 +1,6 @@
|
||||||
int main() {
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue