diff --git a/CMakeLists.txt b/CMakeLists.txt index c1f0190..6a9fc6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,6 +145,7 @@ set(SOURCE_FILE_HEADERS http_client.h stack.h linked_stack.h + circular_queue.h ) if (NOT HAVE_STRPTIME) @@ -194,8 +195,8 @@ if (ENABLE_UTILS_TESTING) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) add_subdirectory(googletest) enable_testing() - add_executable(stack_test test/stack_test.cpp) - target_link_libraries(stack_test GTest::gtest_main utils) + add_executable(unittest test/stack_test.cpp test/queue_test.cpp) + target_link_libraries(unittest GTest::gtest_main utils) include(GoogleTest) - gtest_discover_tests(stack_test) + gtest_discover_tests(unittest) endif() diff --git a/circular_queue.h b/circular_queue.h new file mode 100644 index 0000000..750ce11 --- /dev/null +++ b/circular_queue.h @@ -0,0 +1,131 @@ +#ifndef _UTIL_CIRCULAR_QUEUE_H +#define _UTIL_CIRCULAR_QUEUE_H +#include +#include +#include + +template +struct CircularQueue { + T* base; + size_t front; + size_t rear; + size_t size; +}; + +template +bool init_circular_queue(struct CircularQueue& queue, size_t size) { + if (size < 2) { + return false; + } + queue.base = (T*)malloc(size * sizeof(T)); + if (!queue.base) { + return false; + } + queue.front = 0; + queue.rear = 0; + queue.size = size; + return true; +} + +template +void free_circular_queue(struct CircularQueue& queue, std::function free_func = std::function()) { + if (!queue.base) return; + if (queue.front == queue.rear) return; + if (free_func) { + circular_queue_iter(queue, free_func); + } + free(queue.base); + queue.base = nullptr; + queue.front = 0; + queue.rear = 0; + queue.size = 0; +} + +template +inline void free_circular_queue(struct CircularQueue& queue, F free_func) { + free_circular_queue(queue, std::function(free_func)); +} + +template +void circular_queue_clear(struct CircularQueue& queue, std::function free_func = std::function()) { + if (!queue.base) return; + if (free_func && queue.front != queue.rear) { + circular_queue_iter(queue, free_func); + } + queue.front = 0; + queue.rear = 0; +} + +template +inline void circular_queue_clear(struct CircularQueue& queue, F free_func) { + circular_queue_clear(queue, std::function(free_func)); +} + +template +bool circular_queue_is_empty(struct CircularQueue& queue) { + if (!queue.base) return true; + return queue.front == queue.rear; +} + +template +bool circular_queue_is_full(struct CircularQueue& queue) { + if (!queue.base) return false; + return (queue.rear + 1) % queue.size == queue.front; +} + +template +size_t circular_queue_length(struct CircularQueue& queue) { + if (!queue.base) return 0; + return queue.rear >= queue.front ? queue.rear - queue.front : queue.rear + queue.size - queue.front; +} + +template +bool circular_queue_get_head(struct CircularQueue& queue, T& head) { + if (!queue.base || queue.rear == queue.front) return false; + head = queue.base[queue.front]; + return true; +} + +template +bool circular_queue_get_back(struct CircularQueue& queue, T& back) { + if (!queue.base || queue.rear == queue.front) return false; + size_t pos = queue.rear ? queue.rear - 1 : queue.size - 1; + back = queue.base[pos]; + return true; +} + +template +bool circular_queue_push(struct CircularQueue& queue, T data) { + if (!queue.base) return false; + if ((queue.rear + 1) % queue.size == queue.front) return false; + queue.base[queue.rear++] = data; + queue.rear %= queue.size; + return true; +} + +template +bool circular_queue_pop(struct CircularQueue& queue, T& data) { + if (!queue.base) return false; + if (queue.rear == queue.front) return false; + data = queue.base[queue.front++]; + queue.front %= queue.size; + return true; +} + +template +void circular_queue_iter(struct CircularQueue& queue, std::function callback, Args... args) { + if (!queue.base || !callback) return; + if (queue.front == queue.rear) return; + size_t now = queue.front; + while (now != queue.rear) { + callback(queue.base[now], args...); + now = (now + 1) % queue.size; + } +} + +template +inline void circular_queue_iter(struct CircularQueue& queue, F callback, Args... args) { + circular_queue_iter(queue, std::function(callback), args...); +} + +#endif diff --git a/linked_stack.h b/linked_stack.h index 09dfa1f..c8c2317 100644 --- a/linked_stack.h +++ b/linked_stack.h @@ -37,7 +37,7 @@ void linked_stack_clear(struct LinkedStack*& top, std::function free } template -void linked_stack_clear(struct LinkedStack*& top, F free_func) { +inline void linked_stack_clear(struct LinkedStack*& top, F free_func) { linked_stack_clear(top, std::function(free_func)); } @@ -74,7 +74,7 @@ void linked_stack_iter(struct LinkedStack* top, std::function -void linked_stack_iter(struct LinkedStack* top, F callback, Args... args) { +inline void linked_stack_iter(struct LinkedStack* top, F callback, Args... args) { linked_stack_iter(top, std::function(callback), args...); } diff --git a/test/queue_test.cpp b/test/queue_test.cpp new file mode 100644 index 0000000..2ba430d --- /dev/null +++ b/test/queue_test.cpp @@ -0,0 +1,83 @@ +#include "gtest/gtest.h" +#include "circular_queue.h" +#include + +TEST(Queue_Test, CircularQueue1) { + struct CircularQueue queue; + EXPECT_EQ(init_circular_queue(queue, 3), true); + EXPECT_EQ(circular_queue_is_empty(queue), true); + int v; + EXPECT_EQ(circular_queue_get_back(queue, v), false); + EXPECT_EQ(circular_queue_get_head(queue, v), false); + EXPECT_EQ(circular_queue_pop(queue, v), false); + EXPECT_EQ(circular_queue_push(queue, 1), true); + EXPECT_EQ(circular_queue_push(queue, 2), true); + EXPECT_EQ(circular_queue_is_full(queue), true); + EXPECT_EQ(circular_queue_is_empty(queue), false); + EXPECT_EQ(circular_queue_push(queue, 3), false); + EXPECT_EQ(circular_queue_pop(queue, v), true); + EXPECT_EQ(v, 1); + EXPECT_EQ(circular_queue_is_full(queue), false); + EXPECT_EQ(circular_queue_push(queue, 3), true); + EXPECT_EQ(circular_queue_get_head(queue, v), true); + EXPECT_EQ(v, 2); + EXPECT_EQ(circular_queue_get_back(queue, v), true); + EXPECT_EQ(v, 3); + EXPECT_EQ(circular_queue_length(queue), 2); + EXPECT_EQ(queue.front, 1); + EXPECT_EQ(queue.rear, 0); + std::string text; + circular_queue_iter(queue, [&text](int ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele); + }); + EXPECT_EQ(text, "2,3"); + EXPECT_EQ(circular_queue_pop(queue, v), true); + EXPECT_EQ(v, 2); + EXPECT_EQ(queue.front, 2); + EXPECT_EQ(circular_queue_length(queue), 1); + EXPECT_EQ(circular_queue_push(queue, 4), true); + EXPECT_EQ(circular_queue_pop(queue, v), true); + EXPECT_EQ(v, 3); + EXPECT_EQ(queue.front, 0); + EXPECT_EQ(queue.rear, 1); + circular_queue_clear(queue); + EXPECT_EQ(queue.rear, 0); + EXPECT_EQ(circular_queue_is_empty(queue), true); + free_circular_queue(queue); +} + +TEST(Queue_Test, CircularQueue2) { + struct CircularQueue queue; + EXPECT_EQ(init_circular_queue(queue, 5), true); + EXPECT_EQ(circular_queue_push(queue, 1), true); + EXPECT_EQ(circular_queue_push(queue, 2), true); + EXPECT_EQ(circular_queue_push(queue, 3), true); + EXPECT_EQ(circular_queue_push(queue, 4), true); + std::string text; + circular_queue_iter(queue, [&text](int ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele); + }); + EXPECT_EQ(text, "1,2,3,4"); + int v; + EXPECT_EQ(circular_queue_pop(queue, v), true); + EXPECT_EQ(v, 1); + EXPECT_EQ(circular_queue_push(queue, 5), true); + EXPECT_EQ(circular_queue_length(queue), 4); + EXPECT_EQ(queue.front, 1); + EXPECT_EQ(queue.rear, 0); + text = ""; + circular_queue_iter(queue, [&text](int ele) { + if (!text.empty()) { + text += ","; + } + text += std::to_string(ele); + }); + EXPECT_EQ(text, "2,3,4,5"); + free_circular_queue(queue); +}