Browse Source

对skiplist进行修改,加入线程安全控制和change_size函数,修改函数返回值为更安全的std::variant类型。加入#define.md文档

Gogs 4 months ago
parent
commit
3b24c84ba4
3 changed files with 92 additions and 36 deletions
  1. 14 0
      #define.md
  2. 66 34
      STL/extend/skiplist.h
  3. 12 2
      test.cpp

+ 14 - 0
#define.md

@@ -0,0 +1,14 @@
+# 代码行为控制宏
+
+## 全局
+
+
+#### NANXING_THREAD_     //控制代码线程安全,包括引入各种锁,适用对象包括skiplist.h,默认未定义。
+
+## extend/
+### skiplist.h
+
+#### SKIP_MAX_SIZE    //控制跳表是否有最大限制和在最大限制的行为,当没有最大限制时可以恒定一直插入,有最大限制时当数据量到达上限会返回full而不会进行插入,同时有不同的构造函数,并且引入新的change_size(int)函数,默认未定义。
+
+
+

+ 66 - 34
STL/extend/skiplist.h

@@ -3,6 +3,9 @@
 #include<cstring> 
 #include<exception>
 #include<random>
+#include<shared_mutex>
+#include <variant>
+
 namespace nanxing_extend
 {
     //错误处理机制
@@ -14,7 +17,6 @@ namespace nanxing_extend
         }
     };
 
-    
     class newNode_error:std::exception             //申请新的空间的时候
     {
         const char* what() const noexcept
@@ -30,21 +32,20 @@ namespace nanxing_extend
         }
     };
 
-    
-    
     enum class Skip_result          //跳表操作的结果           
     {
         successufl,
+        
+    #ifdef SKIP_MAX_SIZE
+        full,
+    #endif
+    #ifdef SKIP_MAX_SIZE
+        too_small,
+    #endif
         fault,
-        full
-    };
-    template<typename V>
-    union skiplistre
-    {
-        V value,
-        Skip_result result
+        exit
+
     };
-    
 
     //注意这里的V只能是要么是能直接深拷贝的类型,要么是指向堆上数据的指针类型
     template<typename K,typename V>
@@ -57,9 +58,7 @@ namespace nanxing_extend
     private:
         K key;
         int level;
-        
     public:
-        
         skip_node(){};
         skip_node(K _key,V _value,int _level):key(_key),value(_value),level(_level){};
         init_next(int level)
@@ -76,7 +75,6 @@ namespace nanxing_extend
         K get_key(){ return key; }
     };
 
-
     template<typename K,typename V>
     class skipList
     {
@@ -87,6 +85,9 @@ namespace nanxing_extend
         using ptr=Node*;
         using Nptr=Node**;
         //由于C++的便利性我们考虑使用带头节点的跳表(C++允许对数据不进行初始化(默认构造函数))
+    #ifdef NANXING_THREAD_
+        std::shared_mutex RW_lock;           //读写锁
+    #endif
         Nptr head;                      //头节点
         int max_level;                 //最大高度
         int* random_level;
@@ -94,10 +95,9 @@ namespace nanxing_extend
         int current_size;               //跳表当前尺寸
         //这里出于一个考虑,当跳表单纯作为小数据内存数据库,单表大小限制是没有意义的
         //但是像level_db这样作为KV数据库的缓存的时候,就需要限制大小进行落盘
-
-        #ifdef SKIP_MAX_SIZE
+    #ifdef SKIP_MAX_SIZE
         int max_size;                   //跳表允许的最大尺寸
-        #endif
+    #endif
     public:
         #ifndef SKIP_MAX_SIZE
         skipList(int _max_level):max_level(_max_level),random_level(nullptr)
@@ -114,7 +114,7 @@ namespace nanxing_extend
             }
             catch(std::bad_alloc)
             {
-                throw newNode_error();
+                throw newNode_error();        //重新抛出更详细的错误类型
             }
         }
         #elif
@@ -136,17 +136,26 @@ namespace nanxing_extend
             }
         }
         #endif
+
         [[nodiscard]]                            //这个返回值最好不要忽略否则很有可能会出现内存泄漏
-        skiplistre<V> insert(K _key,V _value)              //如果相同的时候我们考虑将value返回因为value很可能会是一个指针,需要手动清空内存
+        auto insert(K _key,V _value)->std::variant<Skip_result,V>              //如果相同的时候我们考虑将value返回因为value很可能会是一个指针,需要手动清空内存
         {
-            
+        #ifdef NANXING_THREAD_
+            std::lock_guard<std::shared_mutex> lock(RW_lock);             
+        #endif
+        std::variant<Skip_result,V> sk;
+        #ifdef SKIP_MAX_SIZE
+            if(current_size==max_size)
+            {
+                return sk=Skip_result::full;
+            }
+        #endif
             int rand_level=0;
             ptr updata[max_level]={nullptr};          //用于更新的数组
             int level=current_level-1;
             ptr point=head[level];
-            skiplistre<V> sk;
+            
             ptr new_node;
-
             for(int i=level;i>=0;i--)
             {
                 for(;;)
@@ -160,8 +169,7 @@ namespace nanxing_extend
                     {
                         if(point->next_node[level]->key==_key)
                         {
-                            
-                            sk.value=std::move(point->next_node[level]->value);          //这个值已经不需要了,直接移动
+                            sk=std::move(point->next_node[level]->value);          //这个值已经不需要了,直接移动
                             point->next_node[level]->value=_value;
                             return sk;
                         }
@@ -200,17 +208,17 @@ namespace nanxing_extend
                     current_level=rand_level;
                 }
                 current_size++;
-                #ifdef SKIP_MAX_SIZE
-                    return sk.result=Skip_result::full;
-                #endif
             }
-            sk.Skip_result=Skip_result::successufl;
+            sk=Skip_result::successufl;
         }
 
         [[nodiscard]]                    
-        skiplistre<V> search(K _key) noexcept       //不涉及任何内存分配相关任务,因此是异常安全的
+        auto search(K _key)->std::variant<Skip_result,V>  noexcept       //不涉及任何内存分配相关任务,因此是异常安全的
         {
-            skipList<V> sk;
+        #ifdef NANXING_THREAD_
+            std::shared_lock<std::shared_mutex> lock(RW_lock);             
+        #endif        
+            std::variant<Skip_result,V> sk;
             ptr tmp=head[current_level-1];
             int tmp_level=current_level-1;
             for(i=tmp_level;i>=0;i--)
@@ -221,7 +229,7 @@ namespace nanxing_extend
                     {
                         if(tmp->next_node[tmp_level]->key==_key)
                         {
-                            return sk.result=tmp->next_node[tmp_level]->key;
+                            return sk=Skip_result::exit;
                         }
                         else{
                             break;            //跳出开始下一层循环
@@ -232,11 +240,18 @@ namespace nanxing_extend
                     }
                 }
             }
-            return sk.result=Skip_result::fault;
+            return sk=Skip_result::fault;
         }
-        
+                
         void init_skip()                 //直接生成随机数表
         {
+        #ifdef NANXING_THREAD_
+            std::lock_guard<std::shared_mutex> lock(RW_lock);             
+        #endif
+            if(random_level!=nullptr)
+            {
+                return;
+            }            
             try{
                 random_level=new int[1024];                     //刚好是一页的大小(4KB)
             }
@@ -253,7 +268,24 @@ namespace nanxing_extend
         }
     };
 
-    
+    #ifdef SKIP_MAX_SIZE
+    [[nodicard]]
+        auto change_size(int _max_size)->std::variant<Skip_result,V> noexcept
+        {
+            std::variant<
+            if(_max_size>this->max_size)
+            {
+                this->max_size=_max_size;
+                tmp=Skip_result::successufl;
+                return tmp;
+            }
+            else
+            {
+                tmp=Skip_result::too_samll;
+                return tmp;
+            }
+        } 
+    #endif
 }
 
 

+ 12 - 2
test.cpp

@@ -1,10 +1,20 @@
 #include<iostream>
-union stat
+#include<typeinfo>
+template<typename TYPE>
+union ty
 {
-
+    int k,
+    TYPE type
 };
+
 int main()
 {
+    ty<double> t;
+    t.k=15;
+    if(typeid(t)==typeid(double))
+    {
+        std::cout<<"int"<<t.TYPE<<std::endl;
+    }
     int a[10]={0};
     for(auto& i : a)
     {