mskip-list/MSkipList.hpp

244 lines
5.5 KiB
C++
Raw Permalink Normal View History

2024-04-11 09:27:21 +08:00
#ifndef MSKIPLIST_HEADER
#define MSKIPLIST_HEADER
#include <atomic>
#include <cassert>
#include <random>
#include <cstring>
template <typename T, typename P>
class SkipList {
public:
// 插入数据
void insert(const T& key, const P& value);
// 删除数据
void remove(const T& key);
// 查询数据
bool search(const T& key, P& value);
// 是否包含某个数据
bool contains(const T& key);
// 当前表节点个数
std::size_t count() const;
// 清除表
void clear();
public:
SkipList(int max_level = 12);
~SkipList();
private:
struct SkipNode;
std::size_t count_{};
SkipNode** pre_{};
SkipNode* header_{};
const int max_level_{}; // 限定的最大高度
std::atomic_int cur_max_height_{}; // 当前使用的最大高度
std::random_device rd_{};
std::mt19937 gen_{};
std::uniform_int_distribution<int> dis_{};
private:
int random_level();
SkipNode* find_node(const T& key);
};
template <typename T, typename P>
SkipList<T, P>::~SkipList()
{
clear();
delete[] pre_;
delete header_;
}
template <typename T, typename P>
void SkipList<T, P>::clear()
{
SkipNode* start = header_->get_no_bar(0);
while (start) {
SkipNode* n = start;
start = start->get_no_bar(0);
delete n;
--count_;
}
}
template <typename T, typename P>
inline int SkipList<T, P>::random_level()
{
static const int base_ = 2;
int height = 1;
while (height < max_level_ && (dis_(gen_) % base_) == 0) {
++height;
}
return height;
}
template <typename T, typename P>
struct SkipList<T, P>::SkipNode {
T key_{};
P value_{};
int level_{};
public:
explicit SkipNode(int level = 1) { alloc(level); }
~SkipNode() { release(); }
SkipNode(const T& key, const P& value, int level)
{
key_ = key;
value_ = value;
alloc(level);
}
void alloc(int max_level)
{
if (max_level < 1) {
return;
}
release();
next_ = new std::atomic<SkipNode*>[max_level] {};
}
void release() { delete[] next_; }
SkipNode* get(int n)
{
assert(n >= 0);
return next_[n].load(std::memory_order_acquire);
}
SkipNode* get_no_bar(int n)
{
assert(n >= 0);
return next_[n].load(std::memory_order_relaxed);
}
void set(int n, SkipNode* node)
{
assert(n >= 0);
next_[n].store(node, std::memory_order_release);
}
void set_no_bar(int n, SkipNode* node)
{
assert(n >= 0);
next_[n].store(node, std::memory_order_relaxed);
}
private:
std::atomic<SkipNode*>* next_{};
};
template <typename T, typename P>
inline SkipList<T, P>::SkipList(int max_level)
: max_level_(max_level),
cur_max_height_(1),
gen_(rd_()),
dis_(0, std::numeric_limits<int>::max())
{
assert(max_level_ > 0);
header_ = new SkipNode(max_level_);
pre_ = new SkipNode*[max_level_];
}
template <typename T, typename P>
typename SkipList<T, P>::SkipNode* SkipList<T, P>::find_node(const T& key)
{
memset(pre_, 0x0, sizeof(SkipNode*) * max_level_);
SkipNode* x = header_;
int level = cur_max_height_.load() - 1;
while (true) {
SkipNode* next = x->get(level);
if (next && next->key_ < key) {
x = next;
} else {
pre_[level] = x;
if (level == 0) {
return next;
} else {
--level;
}
}
}
}
template <typename T, typename P>
inline bool SkipList<T, P>::contains(const T& key)
{
SkipNode* x = find_node(key);
if (x && x->key_ == key) {
return true;
}
return false;
}
template <typename T, typename P>
inline std::size_t SkipList<T, P>::count() const
{
return count_;
}
template <typename T, typename P>
inline void SkipList<T, P>::insert(const T& key, const P& value)
{
SkipNode* x = find_node(key);
if (x && x->key_ == key) {
x->value_ = value;
return;
}
int height = random_level();
if (height > cur_max_height_) {
for (int i = cur_max_height_; i < height; ++i) {
pre_[i] = header_;
}
cur_max_height_.store(height, std::memory_order_relaxed);
}
x = new SkipNode(key, value, height);
for (int i = 0; i < height; ++i) {
x->set_no_bar(i, pre_[i]->get_no_bar(i));
pre_[i]->set(i, x);
}
++count_;
}
template <typename T, typename P>
inline void SkipList<T, P>::remove(const T& key)
{
memset(pre_, 0x0, sizeof(SkipNode*) * max_level_);
SkipNode* x = header_;
SkipNode* purpose = nullptr;
int level = cur_max_height_.load() - 1;
while (true) {
if (level < 0) {
break;
}
SkipNode* next = x->get(level);
if (!next) {
--level;
continue;
}
if (next->key_ < key) {
x = next;
continue;
}
if (next->key_ == key) {
SkipNode* nx = next->get_no_bar(level);
x->set_no_bar(level, nx);
purpose = next;
}
--level;
}
delete purpose;
--count_;
}
template <typename T, typename P>
inline bool SkipList<T, P>::search(const T& key, P& value)
{
SkipNode* x = find_node(key);
if (x && x->key_ == key) {
value = x->value_;
return true;
}
return false;
}
#endif