#include"basical/type_checking.h" #include #include #include #include namespace nanxing_extend { //错误处理机制 class nextpoint_new:std::exception //skip_node分配空间失败的时候 { const char* what() const noexcept { return "malloc next_node point fault"; } }; class newNode_error:std::exception //申请新的空间的时候 { const char* what() const noexcept { return "malloc new node error"; } }; class random_error:std::exception //申请预设随机数空间的时候 { const char* what() const noexcept { return "malloc random space error"; } }; enum class Skip_result //跳表操作的结果 { successufl, fault, full }; template union skiplistre { V value, Skip_result result }; //注意这里的V只能是要么是能直接深拷贝的类型,要么是指向堆上数据的指针类型 template struct skip_node { static_assert(nanxing_extend::compare_admitvalue); static_assert(nanxing_extend::compare_admitvalue); skip_node** next_node; V value; 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) { try { next_node=::new (skip_node*)[level]; } catch(std::bad_alloc){ //捕获内存分配错误 throw nextpoint_new(); //重新抛出一个定制的更详细的类型用以明确错误的具体位置 } std::memset(next_node,0,sizeof(skip_node*)*level); } K get_key(){ return key; } }; template class skipList { static_assert(nanxing_extend::compare_admitvalue); static_assert(nanxing_extend::compare_admitvalue); private: using Node=skip_node; using Nptr=Node**; //由于C++的便利性我们考虑使用带头节点的跳表(C++允许对数据不进行初始化(默认构造函数)) Nptr head; //头节点 int max_level; //最大高度 int* random_level; int current_level; //跳表当前高度 int current_size; //跳表当前尺寸 //这里出于一个考虑,当跳表单纯作为小数据内存数据库,单表大小限制是没有意义的 //但是像level_db这样作为KV数据库的缓存的时候,就需要限制大小进行落盘 #ifdef SKIP_MAX_SIZE int max_size; //跳表允许的最大尺寸 #endif public: #ifndef SKIP_MAX_SIZE skipList(int _max_level):max_level(_max_level),random_level(nullptr) { try { Node* middle=::new skip_node; middle->init_next(max_level); head=::new (Node*)[max_level]; for(auto& i in head) { i=middle; } } catch(std::bad_alloc) { throw newNode_error(); } } #elif skipList(int _max_level,int _max_size):max_size(_max_size),max_level(_max_level),random_level(nullptr) { try { Node* middle=::new skip_node; middle->init_next(max_level); head=::new (Node*)[max_level]; for(auto& i in head) { i=middle; } } catch(std::bad_alloc) { throw newNode_error(); } } #endif [[nodiscard]] //这个返回值最好不要忽略否则很有可能会出现内存泄漏 skiplistre insert(K _key,V _value) //如果相同的时候我们考虑将value返回因为value很可能会是一个指针,需要手动清空内存 { using ptr=Node*; int rand_level=0; ptr updata[max_level]={nullptr}; //用于更新的数组 int level=current_level-1; ptr point=head[level]; skiplistre sk; ptr new_node; for(int i=level;i>=0;i--) { for(;;) { if(point->next_node[level]==nullptr) { updata[level]=point; break; } else if(point->next_node[level]->key>=_key) { if(point->next_node[level]->key==_key) { sk.value=std::move(point->next_node[level]->value); //这个值已经不需要了,直接移动 point->next_node[level]->value=_value; return sk; } else { updata[level]=point; break; } else{ point=point->head[level]; //更新point指针 } } } [[likely]] if(random_level!=nullptr) { rand_level=random_level[current_size%1024]; new_node=new skip_node(_key,_value,rand_level); } [[unlikely]] else { rand_level=std::rand(chrono::system_clock::now().time_since_epoch().count())%(1+max_level); new_node=new skip_node(_key,_value,rand_level); } ptr tmp=nullptr; for(int i=0;i<=level;i++) { tmp=updata[i]->next_node[i]; updata[i]->next_node[i]=new_node; new_node->next_node[i]=tmp; } } sk.Skip_result=Skip_result::successufl; } skiplistre search(K _key) { } void init_skip() //直接生成随机数表 { try{ random_level=new int[1024]; //刚好是一页的大小(4KB) } catch(std::bad_alloc) { throw random_error(); } std::mt19937 rnd(chrono::system_clock::now().time_since_epoch().count()); for(auto& i :random_level) { i=(rnd()%max_level)+1; } } }; }