mirror of
https://github.com/lifegpc/c-utils.git
synced 2026-06-06 05:08:45 +08:00
Add CircularQueue
This commit is contained in:
@@ -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()
|
||||
|
||||
131
circular_queue.h
Normal file
131
circular_queue.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifndef _UTIL_CIRCULAR_QUEUE_H
|
||||
#define _UTIL_CIRCULAR_QUEUE_H
|
||||
#include <functional>
|
||||
#include <malloc.h>
|
||||
#include <stddef.h>
|
||||
|
||||
template <typename T>
|
||||
struct CircularQueue {
|
||||
T* base;
|
||||
size_t front;
|
||||
size_t rear;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool init_circular_queue(struct CircularQueue<T>& 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 <typename T>
|
||||
void free_circular_queue(struct CircularQueue<T>& queue, std::function<void(T)> free_func = std::function<void(T)>()) {
|
||||
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 <typename T, class F>
|
||||
inline void free_circular_queue(struct CircularQueue<T>& queue, F free_func) {
|
||||
free_circular_queue(queue, std::function<void(T)>(free_func));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void circular_queue_clear(struct CircularQueue<T>& queue, std::function<void(T)> free_func = std::function<void(T)>()) {
|
||||
if (!queue.base) return;
|
||||
if (free_func && queue.front != queue.rear) {
|
||||
circular_queue_iter(queue, free_func);
|
||||
}
|
||||
queue.front = 0;
|
||||
queue.rear = 0;
|
||||
}
|
||||
|
||||
template <typename T, class F>
|
||||
inline void circular_queue_clear(struct CircularQueue<T>& queue, F free_func) {
|
||||
circular_queue_clear(queue, std::function<void(T)>(free_func));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool circular_queue_is_empty(struct CircularQueue<T>& queue) {
|
||||
if (!queue.base) return true;
|
||||
return queue.front == queue.rear;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool circular_queue_is_full(struct CircularQueue<T>& queue) {
|
||||
if (!queue.base) return false;
|
||||
return (queue.rear + 1) % queue.size == queue.front;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t circular_queue_length(struct CircularQueue<T>& queue) {
|
||||
if (!queue.base) return 0;
|
||||
return queue.rear >= queue.front ? queue.rear - queue.front : queue.rear + queue.size - queue.front;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool circular_queue_get_head(struct CircularQueue<T>& queue, T& head) {
|
||||
if (!queue.base || queue.rear == queue.front) return false;
|
||||
head = queue.base[queue.front];
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool circular_queue_get_back(struct CircularQueue<T>& 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 <typename T>
|
||||
bool circular_queue_push(struct CircularQueue<T>& 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 <typename T>
|
||||
bool circular_queue_pop(struct CircularQueue<T>& 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 <typename T, typename ... Args>
|
||||
void circular_queue_iter(struct CircularQueue<T>& queue, std::function<void(T, Args...)> 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 <typename T, class F, typename ... Args>
|
||||
inline void circular_queue_iter(struct CircularQueue<T>& queue, F callback, Args... args) {
|
||||
circular_queue_iter(queue, std::function<void(T, Args...)>(callback), args...);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -37,7 +37,7 @@ void linked_stack_clear(struct LinkedStack<T>*& top, std::function<void(T)> free
|
||||
}
|
||||
|
||||
template <typename T, class F>
|
||||
void linked_stack_clear(struct LinkedStack<T>*& top, F free_func) {
|
||||
inline void linked_stack_clear(struct LinkedStack<T>*& top, F free_func) {
|
||||
linked_stack_clear(top, std::function<void(T)>(free_func));
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ void linked_stack_iter(struct LinkedStack<T>* top, std::function<void(T, Args...
|
||||
}
|
||||
|
||||
template <typename T, class F, typename ... Args>
|
||||
void linked_stack_iter(struct LinkedStack<T>* top, F callback, Args... args) {
|
||||
inline void linked_stack_iter(struct LinkedStack<T>* top, F callback, Args... args) {
|
||||
linked_stack_iter(top, std::function<void(T, Args...)>(callback), args...);
|
||||
}
|
||||
|
||||
|
||||
83
test/queue_test.cpp
Normal file
83
test/queue_test.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "circular_queue.h"
|
||||
#include <string>
|
||||
|
||||
TEST(Queue_Test, CircularQueue1) {
|
||||
struct CircularQueue<int> 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<int> 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);
|
||||
}
|
||||
Reference in New Issue
Block a user