|
@@ -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
|
|
|
}
|
|
|
|
|
|
|