Ver Fonte

V0.9.4
1、新添加了环形队列demo,测试迭代器

Apple há 2 semanas atrás
pai
commit
81e5b6abb0

+ 2 - 2
CMakeLists.txt

@@ -194,8 +194,8 @@ file(GLOB GLOBAL_SRC
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/time)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayer)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/xlsx)
-# add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
-add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ViewModel)
+add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
+# add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ViewModel)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/OpenGLWidgetLibrary)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayerGL)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/OpenGLWidgetTest)

+ 1 - 1
External

@@ -1 +1 @@
-Subproject commit 44b1b143fe3609286dd597d72809be98925aa958
+Subproject commit c594e78049d8f4aa4c5a36b43679d3b7dc21885e

+ 4 - 3
demo/DesignerPattern/CMakeLists.txt

@@ -13,6 +13,7 @@ file(GLOB LOCAL_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
     ${CMAKE_CURRENT_SOURCE_DIR}/AbstractFactory/*.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/Builder/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/Iterator/*.cpp
 )
 
 
@@ -36,8 +37,8 @@ target_include_directories(${this_exe} PRIVATE
 
     ${CMAKE_CURRENT_SOURCE_DIR}/AbstractFactory
     ${CMAKE_CURRENT_SOURCE_DIR}/Builder
-
-    ${spdlog_INCLUDE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/Iterator
+    ${CMAKE_CURRENT_SOURCE_DIR}/Iterator/RingQueue
 )
 
 target_link_libraries(${this_exe} PRIVATE
@@ -51,9 +52,9 @@ target_link_libraries(${this_exe} PRIVATE
 
 target_link_libraries(${this_exe} PRIVATE 
     # ${CURL_LIBRARY}
-    ${spdlog_LIBRARY}
     # ${OpenSSL-1.1.1_LIB_LIBRARY}
     # CURL::libcurl
+    External::spdlog
 )
 
 if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)

+ 0 - 0
demo/DesignerPattern/Iterator/IteratorDemo.cpp


+ 13 - 0
demo/DesignerPattern/Iterator/IteratorDemo.h

@@ -0,0 +1,13 @@
+#ifndef __ITeratorDemo_H__
+#define __ITeratorDemo_H__
+
+#include "RingQueue.hpp"
+
+
+
+
+
+
+
+
+#endif // __ITeratorDemo_H__

+ 647 - 0
demo/DesignerPattern/Iterator/RingQueue/RingQueue.hpp

@@ -0,0 +1,647 @@
+#ifndef RINGQUEUE_H
+#define RINGQUEUE_H
+
+#include <cstdlib>
+#include <utility>
+#include <mutex>
+#include <condition_variable>
+#include <atomic>
+
+/**
+ * @brief 这里采用零公摊的方式,设置多大的空间,就有多大的空间可以使用
+ *        1、m_rear指向最新入队的元素的下一个位置,就是下个将要入队的元素位置
+ *        2、m_front指向需要出队的第一个元素
+ *        3、环形队列自带互斥锁
+ *        
+ * 注意:
+ *      使用时要注意,不带NoBlock的都是阻塞函数
+ *
+ * 判断队列满:
+ *        m_rear == m_front,并且此时都不等于 -1
+ *
+ * 判断队列空:
+ *        m_rear == m_front,并且都等于 -1
+ *
+ * 获取队列大小:
+ *       基本原则就是m_rear后面跟着的是有效值,m_front后面跟着的是已经出队的大小
+ *       m_rear > m_front,返回 m_rear - m_front
+ *       m_front > m_rear,返回 m_capacity - (m_front - m_rear)
+ *       m_rear == m_front,且不等于-1,返回 m_capacity
+ *       m_rear == m_front,且等于-1,返回 0
+ * 
+ * @tparam T 模版类型
+ */
+
+#define _DefaultValue (m_isUseDefaultValue.load() ? m_defaultValue : T{})
+
+template<typename T>
+class RingQueue
+{
+    RingQueue(const RingQueue<T>& queue) = delete;
+    RingQueue<T> operator=(const RingQueue<T>& queue) = delete;
+public:
+    RingQueue();
+    RingQueue(long size);
+    RingQueue(long size, T defaultValue);
+    ~RingQueue();
+
+    /* 入队,默认是阻塞入队 */
+    void push(const T& value);
+    void push(T&& value);
+    bool push_noBlock(const T& value);
+    bool push_noBlock(T&& value);
+    /* 入队,队列满就出队一个,非阻塞 */
+    T push_pop(const T& value);
+
+    /* 出队,删除队列的首个元素
+     * 注意,如果存储的是指针,需要手动释放该指针指向的内存区域,不然会造成内存泄漏 */
+    void pop();
+
+    /* 获取队列中第一个值),但是不出队
+     * 阻塞的方式获取,如果队列为空,会一直阻塞住,直到获取到数据为止 */
+    T front();
+    /* 非阻塞的方式获取,队列为空返回false */
+    bool front_noBlock(T& t);
+    /* 非阻塞方式获取第一个值,如果对列为空,则会返回设置的默认值 */
+    T front_noBlock();
+
+    /* 获取对立第一个数据,获取完立刻出队
+     * 如果队列为空,会阻塞住,直到有数据为止
+     * 如果删除了拷贝构造函数,使用会报错 */
+    T front_pop();
+    /* 非阻塞方式获取第一个值,并出队 */
+    bool front_pop_noBlock(T& t);
+    /* 非阻塞方式获取第一个值,并出队,如果队列为空,会返回设置的默认值 */
+    T front_pop_noBlock();
+    /* 通过移动语义获取数据,获取完成后队列中的数据只是个空壳了,因此直接就出队了 */
+    bool front_pop_move(T& t);
+    bool front_pop_move_noBlock(T& t);
+    
+    /* 设置队列大小 */
+    void setQueueCapacity(long size);
+    /* 设置默认值,给指针类型使用,如果是非阻塞获取,空的时候可以返回为设置的默认值(如nullptr) */
+    void setDefaultValue(T defaultValue);
+    /* 获取队列大小,队列中有效值的大小 */
+    long QueueSize();
+    /* 获取队列容量 */
+    long QueueCapacity();
+    /* 判断队列是否为空 */
+    bool isEmpty();
+    /* 判断队列是否已满 */
+    bool isFull();
+    /* 清空队列 */
+    void clearQueue();
+    /* 退出所有可能的阻塞函数 */
+    void exit();
+
+private:
+    /* 判断是否空 */
+    inline bool _isEmpty();
+    /* 判断是否满 */
+    inline bool _isFull();
+
+private:
+    std::atomic_bool m_isExit = false;      /* 是否退出,这个标识位是为了退出阻塞住的函数 */
+    std::mutex m_mutex;                     /* 互斥锁 */
+    T m_defaultValue;                       /* 默认值 */
+    std::atomic_bool m_isUseDefaultValue = false; /* 是否使用默认值 */
+    T* m_queue = nullptr;                   /* 队列 */
+    long m_capacity = 0;                        /* 队列容量 */
+    long m_front = -1;                          /* 队头 */
+    long m_rear = -1;                           /* 队尾 */
+    std::condition_variable m_cond_NoFull;      /* 非满条件变量 */
+    std::condition_variable m_cond_NoEmpty;     /* 非空条件变量 */
+
+};
+
+
+/* =====================================================================
+ * ***************************** 函数实现 *****************************
+ * ===================================================================== */
+
+/* 这个构造函数需要调用 setQueueSize 设置环形队列的大小 */
+template<typename T>
+RingQueue<T>::RingQueue() 
+{
+    
+}
+
+template<typename T>
+RingQueue<T>::RingQueue(long capacity) 
+{
+    m_capacity = capacity;
+    m_queue = new T[m_capacity] {};
+}
+
+/* 添加默认值 */
+template<typename T>
+RingQueue<T>::RingQueue(long capacity, T defaultValue)
+{
+    m_capacity = capacity;
+    m_queue = new T[m_capacity] {};
+    for(long i = 0; i < m_capacity; i++)
+    {
+        m_queue[i] = defaultValue;
+    }
+    m_defaultValue = defaultValue;
+    m_isUseDefaultValue.store(true); // 设置使用默认值
+}
+
+template<typename T>
+RingQueue<T>::~RingQueue()
+{
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+}
+
+
+/* 清空队列 */
+template<typename T>
+void RingQueue<T>::clearQueue()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+    m_front = -1;
+    m_rear = -1;
+}
+
+
+/*************** 入队 *******************/
+template<typename T>
+void RingQueue<T>::push(const T& value)
+{
+    {
+        std::unique_lock<std::mutex> _lock(m_mutex);
+        m_cond_NoFull.wait(_lock, [this]() {
+            return (!_isFull() || m_isExit);
+        });
+        if(m_isExit)
+        {
+            return;
+        }
+
+        if(m_rear == -1)
+        {
+            m_front = 0;
+            m_rear = 0;
+        }
+
+        m_queue[m_rear] = value;
+        m_rear = (m_rear + 1) % m_capacity;
+    }
+    m_cond_NoEmpty.notify_all();
+}
+
+template<typename T>
+void RingQueue<T>::push(T&& value)
+{
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        m_cond_NoFull.wait(lock, [this](){
+            return (!_isFull() || m_isExit);
+        });
+        if(m_isExit)
+        {
+            return;
+        }
+
+        if(m_rear == -1)
+        {
+            m_front = 0;
+            m_rear = 0;
+        }
+
+        m_queue[m_rear] = std::move(value);
+        m_rear = (m_rear + 1) % m_capacity;
+    }
+
+    m_cond_NoEmpty.notify_all();
+}
+
+/**
+ * @brief 非阻塞的方式入队,如果队列已满,直接返回
+ * 
+ */
+ template<typename T>
+bool RingQueue<T>::push_noBlock(const T& value)
+{
+    {
+        // std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
+        // if(!lock.try_lock())
+        // {
+        //     return false;
+        // }
+        std::lock_guard<std::mutex> lock(m_mutex);
+        /* 先检查队列是否还有剩余空间 */
+        if(_isFull())
+        {
+            return false;
+        }
+        else if(m_rear == -1)
+        {
+            m_front = 0;
+            m_rear = 0;
+        }
+
+        m_queue[m_rear] = value;
+        m_rear = (m_rear + 1) % m_capacity;
+    }
+    m_cond_NoEmpty.notify_all();
+    return true;
+}
+
+template<typename T>
+bool RingQueue<T>::push_noBlock(T&& value)
+{
+    {
+        // std::unique_lock<std::mutex> lock(m_mutex, std::defer_lock);
+        // if(!lock.try_lock())
+        // {
+        //     return false;
+        // }
+        std::lock_guard<std::mutex> lock(m_mutex);
+        /* 先检查队列是否还有剩余空间 */
+        if(_isFull())
+        {
+            return false;
+        }
+        else if(m_rear == -1)
+        {
+            m_front = 0;
+            m_rear = 0;
+        }
+
+        m_queue[m_rear] = std::move(value);
+        m_rear = (m_rear + 1) % m_capacity;
+    }
+    m_cond_NoEmpty.notify_all();
+    return true;
+}
+
+/* 入队,队列满就出队一个,非阻塞 */
+template<typename T>
+T RingQueue<T>::push_pop(const T& value)
+{
+    T ret = _DefaultValue;
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        /* 如果队列已满,先出队一个元素 */
+        if(_isFull())
+        {
+            ret = std::move(m_queue[m_front]);
+            m_front = (m_front + 1) % m_capacity;
+            if(m_front == m_rear)
+            {
+                m_front = -1;
+                m_rear = -1;
+            }
+        }
+        /* 入队新元素 */
+        if(m_rear == -1)
+        {
+            m_front = 0;
+            m_rear = 0;
+        }
+        m_queue[m_rear] = value;
+        m_rear = (m_rear + 1) % m_capacity;
+    }
+    m_cond_NoEmpty.notify_all();
+    return ret;
+}
+
+
+/**
+ * @brief 出队,删除队列的首个元素
+ *        注意,如果存储的是指针,需要手动释放该指针指向的内存区域,不然会造成内存泄漏
+ * 
+ * @tparam T 
+ */
+template<typename T>
+void RingQueue<T>::pop()
+{
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if(_isEmpty())
+        {
+            return;
+        }
+        m_front = (m_front + 1) % m_capacity;
+        if(m_front == m_rear)
+        {
+            m_front = -1;
+            m_rear = -1;
+        }
+    }
+    m_cond_NoFull.notify_all();
+}
+
+
+/* 获取队列中第一个值,但是不出队
+ * 阻塞的方式获取,如果队列为空,会一直阻塞住,直到获取到数据为止 */
+template<typename T>
+T RingQueue<T>::front()
+{
+    
+    std::unique_lock<std::mutex> lock(m_mutex);
+    m_cond_NoEmpty.wait(lock, [this](){
+        return (!_isEmpty() || m_isExit);
+    });
+    if(m_isExit)
+    {
+        return _DefaultValue;
+    }
+    return m_queue[m_front];
+    
+}
+
+
+/* 获取队列中第一个值,但是不出队,非阻塞的方式获取 */
+template<typename T>
+bool RingQueue<T>::front_noBlock(T& t)
+{
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if(_isEmpty())
+        {
+            return false;
+        }
+        t = m_queue[m_front];
+    }
+    return true;
+}
+
+
+/* 非阻塞方式获取第一个值,如果对列为空,则会返回设置的默认值 */
+template<typename T>
+T RingQueue<T>::front_noBlock()
+{
+    std::unique_lock<std::mutex> lock(m_mutex);
+    if(_isEmpty())
+    {
+        return _DefaultValue;
+    }
+    return m_queue[m_front];
+}
+
+/* 获取对立第一个数据,获取完立刻出队
+ * 如果队列为空,会阻塞住,直到有数据为止 */
+template<typename T>
+T RingQueue<T>::front_pop()
+{
+    // T ret = _DefaultValue;
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        m_cond_NoEmpty.wait(lock, [this](){
+            return (!_isEmpty() || m_isExit);
+        });
+        /* 是否退出 */
+        if(m_isExit)
+        {
+            return _DefaultValue;
+        }
+        /* 临时记录索引 */
+        long front = m_front;
+        m_front = (m_front + 1) % m_capacity;
+        if(m_front == m_rear)
+        {
+            m_front = -1;
+            m_rear = -1;
+        }
+        m_cond_NoFull.notify_all();
+        return m_queue[front];
+    }
+}
+
+/* 非阻塞方式获取第一个值,并出队 */
+template<typename T>
+bool RingQueue<T>::front_pop_noBlock(T& t)
+{
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if(_isEmpty())
+        {
+            return false;
+        }
+        t = std::move(m_queue[m_front]);
+        m_front = (m_front + 1) % m_capacity;
+        if(m_front == m_rear)
+        {
+            m_front = -1;
+            m_rear = -1;
+        }
+    }
+    m_cond_NoFull.notify_all();
+    return true;
+}
+
+/* 非阻塞方式获取第一个值,并出队 */
+template<typename T>
+T RingQueue<T>::front_pop_noBlock()
+{
+    // T ret = _DefaultValue;
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        // m_cond_NoEmpty.wait(lock, [this](){
+        //     return (!_isEmpty() || m_isExit);
+        // });
+        if(_isEmpty())
+        {
+            return _DefaultValue;
+        }
+        /* 临时记录索引 */
+        long front = m_front;
+        
+        m_front = (m_front + 1) % m_capacity;
+        if(m_front == m_rear)
+        {
+            m_front = -1;
+            m_rear = -1;
+        }
+        m_cond_NoFull.notify_all();
+        return m_queue[front];
+    }
+}
+
+/* 通过移动语义获取数据,获取完成后队列中的数据只是个空壳了,因此直接就出队了 */
+template<typename T>
+bool RingQueue<T>::front_pop_move(T& t)
+{
+    std::unique_lock<std::mutex> lock(m_mutex);
+    m_cond_NoEmpty.wait(lock, [this]() {
+        return (!_isEmpty() || m_isExit);
+    });
+    /* 是否退出 */
+    if(m_isExit)
+    {
+        return false;
+    }
+    t = std::move(m_queue[m_front]); // 移动语义获取数据
+    m_front = (m_front + 1) % m_capacity;
+    if(m_front == m_rear)
+    {
+        m_front = -1;
+        m_rear = -1;
+    }
+    
+    m_cond_NoFull.notify_all();
+    return true;
+}
+
+template<typename T>
+bool RingQueue<T>::front_pop_move_noBlock(T& t)
+{
+    std::unique_lock<std::mutex> lock(m_mutex);
+    // m_cond_NoEmpty.wait(lock, [this](){
+    //     return (!_isEmpty() || m_isExit);
+    // });
+    if(_isEmpty())
+    {
+        return false;
+    }
+    t = std::move(m_queue[m_front]); // 移动语义获取数据
+    
+    m_front = (m_front + 1) % m_capacity;
+    if(m_front == m_rear)
+    {
+        m_front = -1;
+        m_rear = -1;
+    }
+    m_cond_NoFull.notify_all();
+
+    return true;
+}
+
+
+/**
+ * @brief 设置队列大小
+ *        注意:使用这个设置,如果队列中存储的是指针,指针的内存区域需要在调用这个函数之前释放,不然可能会造成
+ *              内存泄漏
+ * 
+ * @tparam T 
+ * @param size 
+ */
+template<typename T>
+void RingQueue<T>::setQueueCapacity(long size)
+{
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+
+    m_capacity = size;
+    m_front = -1;
+    m_rear = -1;
+    m_queue = new T[m_capacity];
+}
+
+
+/* 设置默认值,给指针类型使用,如果是非阻塞获取,空的时候可以返回为设置的默认值(如nullptr) */
+template<typename T>
+void RingQueue<T>::setDefaultValue(T defaultValue)
+{
+    m_defaultValue = defaultValue;
+    m_isUseDefaultValue.store(true); // 设置使用默认值
+}
+
+/* 获取队列中有效值的大小 */
+template<typename T>
+long RingQueue<T>::QueueSize()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    if(m_rear == -1)
+    {
+        return 0;
+    }
+    else if(m_rear > m_front)
+    {
+        return m_rear - m_front;
+    }
+    else if(m_rear < m_front)
+    {
+        return m_capacity - ( m_front - m_rear );
+    }
+    /* 这时候是队列满 */
+    return m_capacity;
+}
+
+/* 获取队列容量 */
+template<typename T>
+long RingQueue<T>::QueueCapacity()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    return m_capacity;
+}
+
+/**
+ * @brief 判断队列是否为空
+ * 
+ * @tparam T 
+ * @return true 
+ * @return false 
+ */
+template<typename T>
+bool RingQueue<T>::isEmpty()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    return _isEmpty();
+}
+
+/**
+ * @brief 判断队列是否已满,这里判断依赖入队和出队后的队头和队尾指针的位置
+ *        1、队头和队尾指针相等,但是队尾指针不等于-1,表示队列已满
+ * 
+ * @tparam T 
+ * @return true 
+ * @return false 
+ */
+template<typename T>
+bool RingQueue<T>::isFull()
+{
+    std::lock_guard<std::mutex> lock(m_mutex);
+    return _isFull();
+}
+
+/* 退出所有可能的阻塞函数 */
+template<typename T>
+void RingQueue<T>::exit()
+{
+    m_isExit = true;
+    m_cond_NoFull.notify_all();
+    m_cond_NoEmpty.notify_all();
+}
+
+/* 判断是否空 */
+template<typename T>
+bool RingQueue<T>::_isEmpty()
+{
+    if((m_front == m_rear) && (m_front == -1))
+    {
+        return true;
+    }
+    return false;
+}
+
+/* 判断是否满 */
+template<typename T>
+inline bool RingQueue<T>::_isFull()
+{
+    /* 如果m_rear或者m_front不等于-1,说明此时里面有内容
+     * 同时m_front == m_rear,队列就满了 */
+    if(m_front == m_rear && m_rear != -1)
+    {
+        return true;
+    }
+    return false;
+}
+
+
+
+#endif /* RINGQUEUE_H */

+ 520 - 0
demo/DesignerPattern/Iterator/RingQueue/RingQueueManualMutex.hpp

@@ -0,0 +1,520 @@
+#ifndef _RINGQUEUE_MANUAL_MUTEX_HPP_
+#define _RINGQUEUE_MANUAL_MUTEX_HPP_
+
+/**
+ * @brief 这里采用零公摊的方式,设置多大的空间,就有多大的空间可以使用
+ *        1、m_rear指向最新入队的元素的下一个位置,就是下个将要入队的元素位置
+ *        2、m_front指向需要出队的第一个元素
+ *        3、环形队列自带互斥锁,但是不会自动加锁,需要外部手动上锁
+ *        
+ * 使用说明:
+ *      因为是外部手动上锁,所以这里所有的函数都是非阻塞函数
+ *          1、入队时如果队列满,则会自动出队一个元素,入读函数的返回值则是出队的元素,
+ *             如果队列中是指针,需要手动释放
+ *          2、出队时如果队列为空,则会返回默认构建的元素值,尽量设置一个默认元素,会返
+ *             回这个默认元素
+ *
+ * 判断队列满:
+ *        m_rear == m_front,并且此时都不等于 -1
+ *
+ * 判断队列空:
+ *        m_rear == m_front,并且都等于 -1
+ *
+ * 获取队列大小:
+ *       基本原则就是m_rear后面跟着的是有效值,m_front后面跟着的是已经出队的大小
+ *       m_rear > m_front,返回 m_rear - m_front
+ *       m_front > m_rear,返回 m_capacity - (m_front - m_rear)
+ *       m_rear == m_front,且不等于-1,返回 m_capacity
+ *       m_rear == m_front,且等于-1,返回 0
+ * 
+ * @tparam T 模版类型
+ */
+
+#include <atomic>
+#include <mutex>
+#include <iostream>
+
+#define _DefaultValue (m_isUseDefaultValue.load() ? m_defaultValue : T{})
+
+template<typename T>
+class RingQueueManualMutex
+{
+    RingQueueManualMutex(RingQueueManualMutex<T>&& queue) = delete;
+    RingQueueManualMutex<T>& operator=(RingQueueManualMutex<T>&& queue) = delete;
+
+public:
+    RingQueueManualMutex();
+    RingQueueManualMutex(long size);
+    RingQueueManualMutex(long size, T defaultValue);
+    /* 拷贝和赋值构造函数内部都不会自动上锁,需要在外部手动上锁
+     * 如果存储的是指针,需要在外部手动拷贝,否则拷贝的是指针而已 */
+    RingQueueManualMutex(const RingQueueManualMutex<T>& queue);
+    RingQueueManualMutex<T> operator=(const RingQueueManualMutex<T>& queue);
+
+    ~RingQueueManualMutex();
+
+
+
+    /* 入队 */
+    T push(const T& value);
+    T push(T&& value);
+
+    /* 获取队列中第一个值,但是不出队,
+     * 非阻塞的方式获取,如果队列为空,会返回一个默认值 */
+    T front();
+
+    /* 获取对立第一个数据,获取完立刻出队
+     * 如果删除了拷贝构造函数,使用会报错 */
+    T front_pop();
+
+    /* 获取最后一个值,最后一个值不会出队 */
+    T back();
+    bool back(T& value);
+
+    /* 根据下标获取某个位置的元素,下标0就是下一个要出队的位置
+     * 这里获取元素不会出队 */
+    T operator[](long index);
+    T at(long index) const;
+    
+    /* 设置队列大小 */
+    void setQueueCapacity(long size);
+    /* 设置默认值,给指针类型使用,如果是非阻塞获取,空的时候可以返回为设置的默认值(如nullptr) */
+    void setDefaultValue(T defaultValue);
+    /* 获取队列大小,队列中有效值的大小 */
+    long QueueSize() const;
+    /* 获取队列容量 */
+    long QueueCapacity() const;
+    /* 判断队列是否为空 */
+    bool isEmpty() const;
+    /* 判断队列是否已满 */
+    bool isFull() const;
+    /* 清空队列 */
+    void clearQueue();
+
+public:
+    std::mutex mutex;                       /* 互斥锁 */
+private:
+    /* 判断是否空 */
+    inline bool _isEmpty() const;
+    /* 判断是否满 */
+    inline bool _isFull() const;
+
+private:    
+    T m_defaultValue;                           /* 默认值 */
+    std::atomic_bool m_isUseDefaultValue = false; /* 是否使用默认值 */
+    T* m_queue = nullptr;                       /* 队列 */
+    long m_capacity = 0;                        /* 队列容量 */
+    long m_front = -1;                          /* 队头 */
+    long m_rear = -1;                           /* 队尾 */
+    // std::condition_variable m_cond_NoFull;      /* 非满条件变量 */
+    // std::condition_variable m_cond_NoEmpty;     /* 非空条件变量 */
+
+public:
+    /* 定义迭代器 */
+    class Iterator
+    {
+    public:
+        Iterator(T* ptr, long capacity) : m_ptr(ptr), m_capacity(capacity) {}
+
+        T& operator*() { return *m_ptr; }
+        T* operator->() { return m_ptr; }
+
+        Iterator& operator++()
+        {
+            m_ptr = (m_ptr + 1) % m_capacity;
+            return *this;
+        }
+
+        bool operator!=(const Iterator& other) const
+        {
+            return m_ptr != other.m_ptr;
+        }
+
+    private:
+        T* m_ptr;
+        long m_capacity = 0;
+    };
+
+    Iterator begin() { return Iterator(m_queue + m_front, m_capacity); }
+    Iterator end() { return Iterator(m_queue + m_rear, m_capacity); }
+};
+
+
+/* =====================================================================
+ * ***************************** 函数实现 *****************************
+ * ===================================================================== */
+
+/* 这个构造函数需要调用 setQueueSize 设置环形队列的大小 */
+template<typename T>
+RingQueueManualMutex<T>::RingQueueManualMutex() 
+{
+    
+}
+
+template<typename T>
+RingQueueManualMutex<T>::RingQueueManualMutex(long capacity) 
+{
+    m_capacity = capacity;
+    m_queue = new T[m_capacity] {};
+}
+
+/* 添加默认值 */
+template<typename T>
+RingQueueManualMutex<T>::RingQueueManualMutex(long capacity, T defaultValue)
+{
+    m_capacity = capacity;
+    m_queue = new T[m_capacity] {};
+    for(long i = 0; i < m_capacity; i++)
+    {
+        m_queue[i] = defaultValue;
+    }
+    m_defaultValue = defaultValue;
+    m_isUseDefaultValue.store(true); // 设置使用默认值
+}
+
+
+
+template<typename T>
+RingQueueManualMutex<T>::RingQueueManualMutex(const RingQueueManualMutex<T>& queue)
+{
+    m_capacity = queue.m_capacity;
+    m_front = queue.m_front;
+    m_rear = queue.m_rear;
+    m_defaultValue = queue.m_defaultValue;
+    m_isUseDefaultValue.store(queue.m_isUseDefaultValue.load());
+    
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+    
+    if(m_capacity > 0)
+    {
+        m_queue = new T[m_capacity];
+        for(long i = 0; i < m_capacity; i++)
+        {
+            m_queue[i] = queue.m_queue[i];
+        }
+    }
+}
+
+template<typename T>
+RingQueueManualMutex<T> RingQueueManualMutex<T>::operator=(const RingQueueManualMutex<T>& queue)
+{
+    if(this == &queue)
+    {
+        return *this; // 防止自赋值
+    }
+
+    m_capacity = queue.m_capacity;
+    m_front = queue.m_front;
+    m_rear = queue.m_rear;
+    m_defaultValue = queue.m_defaultValue;
+    m_isUseDefaultValue.store(queue.m_isUseDefaultValue.load());
+
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+
+    if(m_capacity > 0)
+    {
+        m_queue = new T[m_capacity];
+        for(long i = 0; i < m_capacity; i++)
+        {
+            m_queue[i] = queue.m_queue[i];
+        }
+    }
+
+    return *this;
+}
+
+
+template<typename T>
+RingQueueManualMutex<T>::~RingQueueManualMutex()
+{
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+}
+
+
+/*************** 入队 *******************/
+template<typename T>
+T  RingQueueManualMutex<T>::push(const T& value)
+{
+    T ret = _DefaultValue; // 默认值
+    if(_isFull())
+    {
+        // std::cout << "RingQueueManualMutex is full, pop one element." << std::endl;
+        /* 队列已满,先出队一个元素 */
+        ret = std::move(m_queue[m_front]);
+        /* 出队后,前进一个位置 */
+        m_front = (m_front + 1) % m_capacity;
+    }
+    // std::cout << "m_front: " << m_front << "  m_rear: " << m_rear << std::endl;
+    if(m_rear == -1)
+    {
+        m_front = 0;
+        m_rear = 0;
+    }
+    m_queue[m_rear] = value;
+    m_rear = (m_rear + 1) % m_capacity;
+
+    return ret;
+}
+
+template<typename T>
+T  RingQueueManualMutex<T>::push(T&& value)
+{
+    T ret = _DefaultValue; // 默认值
+    if(_isFull())
+    {
+        /* 队列已满,先出队一个元素 */
+        ret = std::move(m_queue[m_front]);
+        /* 出队后,前进一个位置 */
+        m_front = (m_front + 1) % m_capacity;
+    }
+    if(m_rear == -1)
+    {
+        m_front = 0;
+        m_rear = 0;
+    }
+    m_queue[m_rear] = std::move(value);
+    m_rear = (m_rear + 1) % m_capacity;
+
+    return ret;
+}
+
+
+/* 获取队列中第一个值,但是不出队
+ * 阻塞的方式获取,如果队列为空,会一直阻塞住,直到获取到数据为止 */
+template<typename T>
+T RingQueueManualMutex<T>::front()
+{
+    if(_isEmpty())
+    {
+        return _DefaultValue; // 如果队列为空,返回默认值
+    }
+    return m_queue[m_front];
+}
+
+
+
+/* 获取对立第一个数据,获取完立刻出队 */
+template<typename T>
+T RingQueueManualMutex<T>::front_pop()
+{
+    if(_isEmpty())
+    {
+        return _DefaultValue; // 如果队列为空,返回默认值
+    }
+    int ret = m_front;
+    // T ret = std::move(m_queue[m_front]);
+    /* 临时记录索引 */
+    m_front = (m_front + 1) % m_capacity;
+    if(m_front == m_rear)
+    {
+        m_front = -1;
+        m_rear = -1;
+    }
+    
+    return std::move(m_queue[ret]);
+}
+
+/* 获取最后一个值,最后一个值不会出队 */
+template<typename T>
+T RingQueueManualMutex<T>::back()
+{
+    if(_isEmpty())
+    {
+        return _DefaultValue; // 如果队列为空,返回默认值
+    }
+    return m_queue[(m_rear - 1 + m_capacity) % m_capacity];
+}
+
+template<typename T>
+bool RingQueueManualMutex<T>::back(T& value)
+{
+    if(_isEmpty())
+    {
+        return false;
+    }
+    value = m_queue[(m_rear - 1 + m_capacity) % m_capacity];
+    return true;
+}
+
+/* 根据下标获取某个位置的元素,下标0就是下一个要出队的位置
+ * 这里获取元素不会出队 */
+template<typename T>
+T RingQueueManualMutex<T>::operator[](long index)
+{
+    if(_isEmpty())
+    {
+        return _DefaultValue; // 如果队列为空,返回默认值
+    }
+    if(index >= QueueSize() || index < -QueueSize())
+    {
+        return _DefaultValue;
+    }
+    if(index < 0)
+    {
+        index += m_capacity; // 处理负数索引
+    }
+    long realIndex = (index + m_front) % m_capacity;
+    
+    return m_queue[realIndex];
+}
+
+
+template<typename T>
+T RingQueueManualMutex<T>::at(long index) const
+{
+    if(_isEmpty())
+    {
+        return _DefaultValue; // 如果队列为空,返回默认值
+    }
+    if(index >= QueueSize() || index < -QueueSize())
+    {
+        return _DefaultValue;
+    }
+    if(index < 0)
+    {
+        index += m_capacity; // 处理负数索引
+    }
+    long realIndex = (index + m_front) % m_capacity;
+    
+    return m_queue[realIndex];
+}
+
+
+/**
+ * @brief 设置队列大小
+ *        注意:使用这个设置,如果队列中存储的是指针,指针的内存区域需要在调用这个函数之前释放,不然可能会造成
+ *              内存泄漏
+ * 
+ * @tparam T 
+ * @param size 
+ */
+template<typename T>
+void RingQueueManualMutex<T>::setQueueCapacity(long size)
+{
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+
+    m_capacity = size;
+    m_front = -1;
+    m_rear = -1;
+    m_queue = new T[m_capacity];
+}
+
+
+/* 设置默认值,给指针类型使用,如果是非阻塞获取,空的时候可以返回为设置的默认值(如nullptr) */
+template<typename T>
+void RingQueueManualMutex<T>::setDefaultValue(T defaultValue)
+{
+    m_defaultValue = defaultValue;
+    m_isUseDefaultValue.store(true); // 设置使用默认值
+}
+
+/* 获取队列中有效值的大小 */
+template<typename T>
+long RingQueueManualMutex<T>::QueueSize() const
+{
+    if(m_rear == -1)
+    {
+        return 0;
+    }
+    else if(m_rear > m_front)
+    {
+        return m_rear - m_front;
+    }
+    else if(m_rear < m_front)
+    {
+        return m_capacity - ( m_front - m_rear );
+    }
+    /* 这时候是队列满 */
+    return m_capacity;
+}
+
+/* 获取队列容量 */
+template<typename T>
+long RingQueueManualMutex<T>::QueueCapacity() const
+{
+    return m_capacity;
+}
+
+/**
+ * @brief 判断队列是否为空
+ * 
+ * @tparam T 
+ * @return true 
+ * @return false 
+ */
+template<typename T>
+bool RingQueueManualMutex<T>::isEmpty() const
+{
+    return _isEmpty();
+}
+
+/**
+ * @brief 判断队列是否已满,这里判断依赖入队和出队后的队头和队尾指针的位置
+ *        1、队头和队尾指针相等,但是队尾指针不等于-1,表示队列已满
+ * 
+ * @tparam T 
+ * @return true 
+ * @return false 
+ */
+template<typename T>
+bool RingQueueManualMutex<T>::isFull() const
+{
+    return _isFull();
+}
+
+/* 清空队列 */
+template<typename T>
+void RingQueueManualMutex<T>::clearQueue()
+{
+    if(m_queue != nullptr)
+    {
+        delete[] m_queue;
+        m_queue = nullptr;
+    }
+    m_front = -1;
+    m_rear = -1;
+}
+
+/* 判断是否空 */
+template<typename T>
+bool RingQueueManualMutex<T>::_isEmpty() const
+{
+    if((m_front == m_rear) && (m_front == -1))
+    {
+        return true;
+    }
+    return false;
+}
+
+/* 判断是否满 */
+template<typename T>
+inline bool RingQueueManualMutex<T>::_isFull() const
+{
+    /* 如果m_rear或者m_front不等于-1,说明此时里面有内容
+     * 同时m_front == m_rear,队列就满了 */
+    if(m_front == m_rear && m_rear != -1)
+    {
+        return true;
+    }
+    return false;
+}
+
+
+
+#endif /* _RINGQUEUE_MANUAL_MUTEX_HPP_ */

+ 2 - 0
demo/DesignerPattern/main.cpp

@@ -47,5 +47,7 @@ int main(int argc, char *argv[])
     delete translator;
     delete french;
 
+
+
     return a.exec();
 }

+ 1 - 5
demo/ViewModel/CMakeLists.txt

@@ -50,11 +50,7 @@ target_link_libraries(${this_exe} PRIVATE
 )
 
 target_link_libraries(${this_exe} PRIVATE 
-    # ${CURL_LIBRARY}
-    # ${spdlog_LIBRARY}
-    # ${OpenSSL-1.1.1_LIB_LIBRARY}
-    # CURL::libcurl
-    spdlog::spdlog
+    External::spdlog
 )
 
 if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)