Blink DB Documentation v1.0.0
Blink DB Documentation
Loading...
Searching...
No Matches
skiplist.hpp
Go to the documentation of this file.
1
10#ifndef SKIP_LIST
11#define SKIP_LIST
12
13#include "key_value.hpp"
14#include <random>
15
23enum class SentinelType {
24 NEGATIVE_INFINITY,
25 NORMAL,
26 POSITIVE_INFINITY,
27};
28
37class Node {
38public:
39 SentinelType type;
40 KeyValuePair data;
41 Node *prev;
42 Node *next;
43 Node *up;
44 Node *down;
45
46 Node(SentinelType type, const KeyValuePair &data)
47 : type(type), data(data), prev(nullptr), next(nullptr), up(nullptr), down(nullptr) {}
48};
49
55class SkipList {
56private:
57 static constexpr int MAX_LEVEL = 16;
58 static constexpr double P = 0.5;
59 std::mt19937 gen;
60 std::uniform_real_distribution<> dis;
61 Node *head;
62 Node *tail;
63 int current_level;
64 size_t totalSize;
65
66public:
67 SkipList() : gen(std::random_device()()), dis(0, 1), current_level(0), totalSize(0) {
68 head = new Node(SentinelType::NEGATIVE_INFINITY, KeyValuePair());
69 tail = new Node(SentinelType::POSITIVE_INFINITY, KeyValuePair());
70 head->next = tail;
71 tail->prev = head;
72 }
73
83 Node *search(const std::string &key) {
84 Node *cur = head;
85 while (true) {
86 while (cur->next->type != SentinelType::POSITIVE_INFINITY &&
87 cur->next->data.getKey() <= key) {
88 cur = cur->next;
89 }
90 if (cur->down != nullptr) {
91 cur = cur->down;
92 } else {
93 break;
94 }
95 }
96 return cur;
97 }
98
106 std::pair<bool, std::string> get(const std::string &key) {
107 Node *cur = search(key);
108 if (cur->data.getKey() == key) {
109 return {true, cur->data.getValue()};
110 }
111 return {false, ""};
112 }
113
123 void put(const std::string &key, const std::string &value) {
124 Node *current = search(key);
125 if (current->data.getKey() == key) {
126 current->data.setValue(value);
127 return;
128 }
129 KeyValuePair kv(key, value);
130 totalSize += kv.size();
131 Node *newNode = new Node(SentinelType::NORMAL, kv);
132 newNode->prev = current;
133 newNode->next = current->next;
134 current->next->prev = newNode;
135 current->next = newNode;
136
137 int i = 0;
138 while (i < MAX_LEVEL && dis(gen) < P) {
139 if (i >= current_level) {
140 current_level++;
141 Node *newHead = new Node(SentinelType::NEGATIVE_INFINITY, KeyValuePair());
142 Node *newTail = new Node(SentinelType::POSITIVE_INFINITY, KeyValuePair());
143 newHead->next = newTail;
144 newTail->prev = newHead;
145 newHead->down = head;
146 newTail->down = tail;
147 head->up = newHead;
148 tail->up = newTail;
149 head = newHead;
150 tail = newTail;
151 }
152 while (current->up == nullptr) {
153 current = current->prev;
154 }
155 current = current->up;
156 Node *newNodeUp = new Node(SentinelType::NORMAL, KeyValuePair(key, ""));
157 newNodeUp->prev = current;
158 newNodeUp->next = current->next;
159 current->next->prev = newNodeUp;
160 current->next = newNodeUp;
161 newNode->up = newNodeUp;
162 newNodeUp->down = newNode;
163 newNode = newNodeUp;
164 i++;
165 }
166 }
167
172 size_t getSize() {
173 return totalSize;
174 }
175
181 class Iterator {
182 private:
183 Node *current;
184
185 public:
186 using iterator_category = std::forward_iterator_tag;
187 using value_type = KeyValuePair;
188 using difference_type = std::ptrdiff_t;
189 using pointer = KeyValuePair *;
190 using reference = KeyValuePair &;
191
192 Iterator(Node *node = nullptr) : current(node) {}
193
194 reference operator*() const {
195 return current->data;
196 }
197 pointer operator->() const {
198 return &(current->data);
199 }
200
201 Iterator &operator++() {
202 if (current) {
203 current = current->next;
204 if (current && current->type == SentinelType::POSITIVE_INFINITY) {
205 current = nullptr;
206 }
207 }
208 return *this;
209 }
210 Iterator operator++(int) {
211 Iterator temp = *this;
212 ++(*this);
213 return temp;
214 }
215 bool operator==(const Iterator &other) const {
216 return current == other.current;
217 }
218 bool operator!=(const Iterator &other) const {
219 return !(*this == other);
220 }
221 };
222
223 Iterator begin() {
224 Node *current = head;
225 while (current->down != nullptr) {
226 current = current->down;
227 }
228 current = current->next;
229
230 if (current->type == SentinelType::POSITIVE_INFINITY) {
231 return end();
232 }
233
234 return Iterator(current);
235 }
236
237 Iterator end() {
238 return Iterator(nullptr);
239 }
240
241 Iterator find(const std::string &key) {
242 Node *node = search(key);
243 if (node->data.getKey() == key && node->type == SentinelType::NORMAL) {
244 return Iterator(node);
245 }
246 return end();
247 }
248
249 ~SkipList() {
250 Node *cur = head;
251 while (cur != nullptr) {
252 Node *next = cur->down;
253 Node *tmp = cur;
254 while (tmp != nullptr) {
255 Node *tmpNext = tmp->next;
256 delete tmp;
257 tmp = tmpNext;
258 }
259 cur = next;
260 }
261 }
262};
263
264#endif
Key-Value Pair Class.
Definition key_value.hpp:19
void setValue(const std::string &newValue)
Set the Value object.
Definition key_value.hpp:44
const std::string & getValue() const
Get the Value object.
Definition key_value.hpp:58
size_t size() const
Get the Size of the Key Value Pair object.
Definition key_value.hpp:66
const std::string & getKey() const
Get the Key object.
Definition key_value.hpp:51
Skip List Node Class.
Definition skiplist.hpp:37
A Iterator class for the skip list.
Definition skiplist.hpp:181
Node * search(const std::string &key)
Search for a key in the skip list.
Definition skiplist.hpp:83
void put(const std::string &key, const std::string &value)
This method inserts a key-value pair into the skip list.
Definition skiplist.hpp:123
size_t getSize()
Get the size of the skip list.
Definition skiplist.hpp:172
std::pair< bool, std::string > get(const std::string &key)
This method retrieves the value associated with a given key in the skip list.
Definition skiplist.hpp:106
Key-Value Pair Class.
SentinelType
To represent the type of node in the skip list.
Definition skiplist.hpp:23