-[submodule "cpp_impl/RingBuffer"]
- path = cpp_impl/RingBuffer
- url = https://github.com/Stephen-Seo/RingBuffer.git
set(UDPConnection_VERSION 1.0)
-if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/RingBuffer/src)
- message(FATAL_ERROR "RingBuffer is missing!\nPlease update the \
-RingBuffer submodule by running 'git submodule init' and 'git submodule \
-update'!")
-endif()
-
set(UDPConnection_SOURCES
src/UDPConnection.cpp
)
target_include_directories(UDPConnection PUBLIC ${LIBSODIUM_INCLUDE_DIRS})
target_compile_options(UDPConnection PUBLIC ${LIBSODIUM_CFLAGS_OTHER})
-target_include_directories(UDPConnection PUBLIC
- "${CMAKE_CURRENT_SOURCE_DIR}/RingBuffer/src")
-
if(CMAKE_BUILD_TYPE MATCHES "Debug")
find_package(GTest QUIET)
if(GTEST_FOUND)
set(UDPC_UnitTest_SOURCES
src/test/UDPC_UnitTest.cpp
- src/test/TestTSQueue.cpp
src/test/TestTSLQueue.cpp
src/test/TestUDPC.cpp
)
+++ /dev/null
-Subproject commit 2873bfb55467a9b236382b77db18408a661c4542
+++ /dev/null
-#ifndef UDPC_THREADSAFE_QUEUE_HPP
-#define UDPC_THREADSAFE_QUEUE_HPP
-
-#define UDPC_TSQUEUE_DEFAULT_CAPACITY 32
-
-#include <cstdlib>
-#include <memory>
-#include <mutex>
-#include <optional>
-
-#include <RB/RingBuffer.hpp>
-
-template <typename T>
-class TSQueue {
- public:
- TSQueue(unsigned int capacity = UDPC_TSQUEUE_DEFAULT_CAPACITY);
- ~TSQueue();
-
- // disable copy
- TSQueue(const TSQueue &other) = delete;
- TSQueue &operator=(const TSQueue &other) = delete;
- // enable move
- TSQueue(TSQueue &&other);
- TSQueue &operator=(TSQueue &&other);
-
- bool push(const T &data);
- std::optional<T> top();
- bool pop();
- std::optional<T> top_and_pop();
- std::optional<T> top_and_pop_and_rsize(unsigned int *rsize);
- void clear();
- /*
- * status ==
- * 0 - success
- * 1 - success, but previous size was reduced
- */
- void changeCapacity(unsigned int newCapacity, unsigned int *status);
- unsigned int size();
- unsigned int capacity();
- unsigned int remaining_capacity();
- bool empty();
- bool full();
-
- private:
- std::mutex mutex;
- RB::RingBuffer<T> rb;
-};
-
-template <typename T>
-TSQueue<T>::TSQueue(unsigned int capacity) :
-mutex(),
-rb(capacity)
-{
- rb.setResizePolicy(false);
-}
-
-template <typename T>
-TSQueue<T>::TSQueue(TSQueue &&other) :
-TSQueue<T>::TSQueue(other.rb.getCapacity())
-{
- std::lock_guard<std::mutex> lock(other.mutex);
- for(unsigned int i = 0; i < other.rb.getSize(); ++i) {
- rb.push(other.rb[i]);
- }
-}
-
-template <typename T>
-TSQueue<T>& TSQueue<T>::operator =(TSQueue &&other)
-{
- std::scoped_lock lock(other.mutex, mutex);
- rb.resize(0);
- rb.changeCapacity(other.rb.getCapacity());
- for(unsigned int i = 0; i < other.rb.getSize(); ++i) {
- rb.push(other.rb[i]);
- }
-}
-
-template <typename T>
-TSQueue<T>::~TSQueue()
-{}
-
-template <typename T>
-bool TSQueue<T>::push(const T &data) {
- std::lock_guard<std::mutex> lock(mutex);
- if(rb.getSize() == rb.getCapacity()) {
- return false;
- }
- rb.push(data);
- return true;
-}
-
-template <typename T>
-std::optional<T> TSQueue<T>::top() {
- std::lock_guard<std::mutex> lock(mutex);
- std::optional<T> value = std::nullopt;
- if(!rb.empty()) {
- value = rb.top();
- }
- return value;
-}
-
-template <typename T>
-bool TSQueue<T>::pop() {
- std::lock_guard<std::mutex> lock(mutex);
- if(rb.empty()) {
- return false;
- }
- rb.pop();
- return true;
-}
-
-template <typename T>
-std::optional<T> TSQueue<T>::top_and_pop() {
- std::lock_guard<std::mutex> lock(mutex);
- std::optional<T> value = std::nullopt;
- if(!rb.empty()) {
- value = rb.top();
- rb.pop();
- }
- return value;
-}
-
-template <typename T>
-std::optional<T> TSQueue<T>::top_and_pop_and_rsize(unsigned int *rsize) {
- std::lock_guard<std::mutex> lock(mutex);
- std::optional<T> value = std::nullopt;
- if(!rb.empty()) {
- value = rb.top();
- rb.pop();
- }
- if(rsize) {
- *rsize = rb.getSize();
- }
- return value;
-}
-
-template <typename T>
-void TSQueue<T>::clear() {
- std::lock_guard<std::mutex> lock(mutex);
- rb.resize(0);
-}
-
-template <typename T>
-void TSQueue<T>::changeCapacity(unsigned int newCapacity, unsigned int *status) {
- std::lock_guard<std::mutex> lock(mutex);
- if(status) {
- if(rb.getSize() < newCapacity) {
- *status = 1;
- } else {
- *status = 0;
- }
- }
- rb.changeCapacity(newCapacity);
-}
-
-template <typename T>
-unsigned int TSQueue<T>::size() {
- std::lock_guard<std::mutex> lock(mutex);
- unsigned int size = rb.getSize();
- return size;
-}
-
-template <typename T>
-unsigned int TSQueue<T>::capacity() {
- std::lock_guard<std::mutex> lock(mutex);
- unsigned int capacity = rb.getCapacity();
- return capacity;
-}
-
-template <typename T>
-unsigned int TSQueue<T>::remaining_capacity() {
- std::lock_guard<std::mutex> lock(mutex);
- unsigned int remaining = rb.getCapacity() - rb.getSize();
- return remaining;
-}
-
-template <typename T>
-bool TSQueue<T>::empty() {
- // No lock required, since this is calling size() that uses a lock
- unsigned int size = this->size();
- return size == 0;
-}
-
-template <typename T>
-bool TSQueue<T>::full() {
- // No lock required, calling remaining_capacity() that uses a lock
- unsigned int remaining = remaining_capacity();
- return remaining == 0;
-}
-
-#endif
#include <mutex>
#include <iostream>
-#include "TSQueue.hpp"
#include "TSLQueue.hpp"
#include "UDPConnection.h"
+++ /dev/null
-#include <gtest/gtest.h>
-
-#include <cstdio>
-#include <future>
-
-#include "TSQueue.hpp"
-
-TEST(TSQueue, Usage)
-{
- TSQueue<int> q(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);
- EXPECT_EQ(100, q.top());
-
- // { 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);
-
- EXPECT_EQ(100, q.top());
-
- EXPECT_TRUE(q.pop());
- EXPECT_EQ(q.size(), 3);
-
- // { 200, 300, 400 }
-
- EXPECT_EQ(200, q.top());
-
- temp = 1;
- EXPECT_TRUE(q.push(temp));
- EXPECT_EQ(q.size(), 4);
-
- // { 200, 300, 400, 1 }
-
- EXPECT_EQ(200, q.top());
-
- temp = 2;
- EXPECT_FALSE(q.push(temp));
- EXPECT_EQ(q.size(), 4);
-
- q.changeCapacity(8, nullptr);
- EXPECT_EQ(q.size(), 4);
-
- temp = 10;
- EXPECT_TRUE(q.push(temp));
- EXPECT_EQ(q.size(), 5);
-
- // { 200, 300, 400, 1, 10 }
-
- EXPECT_EQ(200, q.top());
-
- EXPECT_TRUE(q.pop());
- EXPECT_EQ(q.size(), 4);
-
- // { 300, 400, 1, 10 }
-
- EXPECT_EQ(300, q.top());
-
- EXPECT_TRUE(q.pop());
- EXPECT_EQ(q.size(), 3);
-
- // { 400, 1, 10 }
-
- EXPECT_EQ(400, q.top());
-
- q.changeCapacity(1, nullptr);
-
- // { 10 }
-
- EXPECT_EQ(q.size(), 1);
-
- EXPECT_EQ(10, q.top());
-
- EXPECT_TRUE(q.pop());
-
- // { }
-
- EXPECT_FALSE(q.pop());
- EXPECT_EQ(0, q.size());
-}
-
-TEST(TSQueue, Concurrent)
-{
- TSQueue<int> q(4);
-
- auto a0 = std::async(std::launch::async, [&q] () {int i = 0; return q.push(i); });
- auto a1 = std::async(std::launch::async, [&q] () {int i = 1; return q.push(i); });
- auto a2 = std::async(std::launch::async, [&q] () {int i = 2; return q.push(i); });
- auto a3 = std::async(std::launch::async, [&q] () {int i = 3; return q.push(i); });
- auto a4 = std::async(std::launch::async, [&q] () {int i = 4; return q.push(i); });
-
- bool results[] = {
- a0.get(),
- a1.get(),
- a2.get(),
- a3.get(),
- a4.get()
- };
-
- int insertCount = 0;
- for(int i = 0; i < 5; ++i) {
- if(results[i]) {
- ++insertCount;
- }
- }
-
- EXPECT_EQ(insertCount, 4);
- EXPECT_EQ(q.size(), 4);
-
- int top;
- for(int i = 0; i < 4; ++i) {
- top = q.top().value();
- EXPECT_TRUE(q.pop());
- EXPECT_EQ(q.size(), 3 - i);
- printf("%d ", top);
- }
- printf("\n");
-
- EXPECT_FALSE(q.pop());
- EXPECT_EQ(q.size(), 0);
-}