blob: 1243a715ae3c9f1dd08c2a458e73ba183b38957d [file] [log] [blame]
Shuo Chen9a43f162014-07-01 13:43:54 +08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3* Copyright (c) 2014, Regents of the University of California.
4*
5* This file is part of NDN repo-ng (Next generation of NDN repository).
6* See AUTHORS.md for complete list of repo-ng authors and contributors.
7*
8* repo-ng is free software: you can redistribute it and/or modify it under the terms
9* of the GNU General Public License as published by the Free Software Foundation,
10* either version 3 of the License, or (at your option) any later version.
11*
12* repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14* PURPOSE. See the GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License along with
17* repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#ifndef REPO_STORAGE_SKIPLIST_HPP
21#define REPO_STORAGE_SKIPLIST_HPP
22
23#include "common.hpp"
24
Shuo Chen9a43f162014-07-01 13:43:54 +080025namespace repo {
26
Shuo Chenbf2248d2014-07-12 13:47:20 +080027class SkipList32Levels25Probabilty
Shuo Chen9a43f162014-07-01 13:43:54 +080028{
29public:
30 static size_t
Shuo Chenbf2248d2014-07-12 13:47:20 +080031 getMaxLevels()
Shuo Chen9a43f162014-07-01 13:43:54 +080032 {
33 return 32;
34 }
35
36 static double
37 getProbability()
38 {
Shuo Chenbf2248d2014-07-12 13:47:20 +080039 return 0.25; // 25%
Shuo Chen9a43f162014-07-01 13:43:54 +080040 }
41};
42
Shuo Chenbf2248d2014-07-12 13:47:20 +080043template<typename T>
44struct SkipListNode
45{
46 typedef SkipListNode<T>* SkipListNodePointer;
47 T data;
48 std::vector<SkipListNodePointer> prevs;
49 std::vector<SkipListNodePointer> nexts;
50};
51
52template<typename T, class Ref, class Ptr>
53class SkipListIterator : public std::iterator<std::bidirectional_iterator_tag, T>
54{
55public:
56 typedef SkipListNode<T>* NodePointer;
57 NodePointer node;
58
59 typedef SkipListIterator<T, Ref, Ptr> Self;
60 typedef T value_type;
61 typedef Ptr pointer;
62 typedef Ref reference;
63 typedef ptrdiff_t difference_type;
64 typedef SkipListIterator<T, const T&, const T*> const_iterator;
65 /// alias of const_iterator
66 typedef const_iterator iterator;
67
68public:
69 // constructor
70 SkipListIterator()
71 {
72 }
73
74 explicit
75 SkipListIterator(NodePointer x)
76 : node(x)
77 {
78 }
79
80 SkipListIterator(const SkipListIterator& x)
81 : node(x.node)
82 {
83 }
84
85 bool
86 operator==(const const_iterator& x) const
87 {
88 return node == x.node;
89 }
90
91 bool
92 operator!=(const const_iterator& x) const
93 {
94 return node != x.node;
95 }
96
97 reference
98 operator*() const
99 {
100 return (*node).data;
101 }
102
103 pointer
104 operator->() const
105 {
106 return &(operator*());
107 }
108
109 Self&
110 operator++()
111 {
112 node = node->nexts[0];
113 return *this;
114 }
115
116 Self
117 operator++(int)
118 {
119 Self tmp = *this;
120 ++*this;
121 return tmp;
122 }
123
124 Self&
125 operator--()
126 {
127 node = node->prevs[0];
128 return *this;
129 }
130
131 Self
132 operator--(int)
133 {
134 Self tmp = *this;
135 --*this;
136 return tmp;
137 }
138};
139
140/*
141 * @brief SkipList
142 *
143 * Examples of internal structure:
144 * "A <-i-> B" means A->nexts[i] = B and B->prevs[i] = A
145 *
146 * case 1: an empty skip list
147 * m_head <-0-> m_head
148 *
149 * case 2: a skip list with only one level and only one node
150 * m_head <-0-> A <-0-> m_head
151 *
152 * case 3: a skip list with three nodes, node A and B appear on one level,
153 * node C appears on two levels
154 * m_head <-1-> C <-1-> m_head
155 * m_head <-0-> A <-0-> B <-0-> C <-0-> m_head
156 */
157
Shuo Chen9a43f162014-07-01 13:43:54 +0800158template<typename T, typename Compare = std::less<T>,
Shuo Chenbf2248d2014-07-12 13:47:20 +0800159 typename Traits = SkipList32Levels25Probabilty>
Shuo Chen9a43f162014-07-01 13:43:54 +0800160class SkipList
161{
162public:
Shuo Chenbf2248d2014-07-12 13:47:20 +0800163 typedef T value_type;
164 typedef value_type* pointer;
165 typedef const value_type* const_pointer;
166 typedef value_type& reference;
167 typedef const value_type& const_reference;
168 typedef SkipListNode<T> Node;
169 typedef Node* NodePointer;
170 typedef size_t size_type;
171 typedef ptrdiff_t difference_type;
172 typedef SkipListIterator<T, const T&, const T*> const_iterator;
173 /// alias of const_iterator
174 typedef const_iterator iterator;
Shuo Chen9a43f162014-07-01 13:43:54 +0800175
176public:
177 explicit
Shuo Chenbf2248d2014-07-12 13:47:20 +0800178 SkipList()
179 {
180 initializeHead();
181 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800182
Shuo Chenbf2248d2014-07-12 13:47:20 +0800183 ~SkipList()
184 {
185 clear();
186 deallocateNode(m_head);
187 }
188
189 const_iterator
190 begin() const
191 {
192 return const_iterator(*(*m_head).nexts.begin());
193 }
194
195 const_iterator
196 end() const
197 {
198 return const_iterator(m_head);
199 }
200
201 bool
202 empty() const
203 {
204 return *(m_head->nexts.begin()) == m_head;
205 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800206
207 size_t
Shuo Chenbf2248d2014-07-12 13:47:20 +0800208 size() const
209 {
210 return m_size;
211 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800212
Shuo Chenbf2248d2014-07-12 13:47:20 +0800213 const_iterator
214 lower_bound(const T& x) const;
Shuo Chen9a43f162014-07-01 13:43:54 +0800215
Shuo Chenbf2248d2014-07-12 13:47:20 +0800216 const_iterator
217 find(const T& x) const;
Shuo Chen9a43f162014-07-01 13:43:54 +0800218
Shuo Chenbf2248d2014-07-12 13:47:20 +0800219 std::pair<const_iterator, bool>
220 insert(const T& x);
Shuo Chen9a43f162014-07-01 13:43:54 +0800221
Shuo Chenbf2248d2014-07-12 13:47:20 +0800222 const_iterator
223 erase(const_iterator it);
Shuo Chen9a43f162014-07-01 13:43:54 +0800224
Shuo Chenbf2248d2014-07-12 13:47:20 +0800225protected:
226 /*
227 * @brief allocate memory for node
228 */
229 NodePointer
230 allocateNode()
231 {
232 return m_skiplistAllocator.allocate(sizeof(Node));
233 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800234
Shuo Chenbf2248d2014-07-12 13:47:20 +0800235 /*
236 * @brief deallocate memory of node
237 */
238 void
239 deallocateNode(NodePointer p)
240 {
241 m_skiplistAllocator.deallocate(p, sizeof(Node));
242 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800243
Shuo Chenbf2248d2014-07-12 13:47:20 +0800244 /*
245 * @brief initialize the node
246 */
247 NodePointer
248 createNode()
249 {
250 NodePointer p = allocateNode();
251 Node node;
252 m_skiplistAllocator.construct(p, node);
253 return p;
254 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800255
Shuo Chenbf2248d2014-07-12 13:47:20 +0800256 /*
257 * @brief initialize the node with given value
258 * @para to be set to the value of node
259 */
260 NodePointer
261 createNode(const T& x)
262 {
263 NodePointer p = allocateNode();
264 Node node;
265 m_skiplistAllocator.construct(p, node);
266 m_dataAllocator.construct(&(p->data), x);
267 return p;
268 }
269
270 /*
271 * @brief destructror of the node
272 * @para given pointer of node to be destructed
273 */
274 void
275 destroyNode(NodePointer p)
276 {
277 m_skiplistAllocator.destroy(p);
278 deallocateNode(p);
279 }
280
281 /*
282 * @brief initialize the head
283 */
284 void
285 initializeHead()
286 {
287 m_head = createNode();
288 m_head->prevs.push_back(m_head);
289 m_head->nexts.push_back(m_head);
290 m_size = 0;
291 }
292
293 /*
294 * @brief destroy all the nodes of skiplist except the head
295 */
296 void
297 clear()
298 {
299 NodePointer cur = m_head->nexts[0];
300 while (cur != m_head) {
301 NodePointer tmp = cur;
302 cur = cur->nexts[0];
303 destroyNode(tmp);
304 }
305 m_head->nexts[0] = m_head;
306 m_head->prevs[0] = m_head;
307 }
308
309 /*
310 * @brief pick a random height for inserted skiplist entry
311 */
Shuo Chen9a43f162014-07-01 13:43:54 +0800312 size_t
Shuo Chenbf2248d2014-07-12 13:47:20 +0800313 pickRandomLevel() const
314 {
315 static boost::random::mt19937 gen;
316 static boost::random::geometric_distribution<size_t> dist(Traits::getProbability());
317 return std::min(dist(gen), Traits::getMaxLevels());
318 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800319
Shuo Chenbf2248d2014-07-12 13:47:20 +0800320protected:
321 NodePointer m_head;
322 std::allocator<Node> m_skiplistAllocator;
323 std::allocator<T> m_dataAllocator;
Shuo Chen9a43f162014-07-01 13:43:54 +0800324 Compare m_compare;
Shuo Chenbf2248d2014-07-12 13:47:20 +0800325 size_t m_size;
Shuo Chen9a43f162014-07-01 13:43:54 +0800326};
327
Shuo Chenbf2248d2014-07-12 13:47:20 +0800328
Shuo Chen9a43f162014-07-01 13:43:54 +0800329template<typename T, typename Compare, typename Traits>
Shuo Chenbf2248d2014-07-12 13:47:20 +0800330typename SkipList<T, Compare, Traits>::const_iterator
331SkipList<T, Compare, Traits>::lower_bound(const T& x) const
Shuo Chen9a43f162014-07-01 13:43:54 +0800332{
Shuo Chenbf2248d2014-07-12 13:47:20 +0800333 size_t nLevels = m_head->nexts.size();
334 NodePointer p = m_head;
335 NodePointer q = p->nexts[nLevels - 1];
336 for (int i = nLevels - 1; i >= 0; --i) {
337 q = p->nexts[i];
338 if (q != m_head) {
339 while (m_compare(q->data, x)) {
340 p = p->nexts[i];
341 q = p->nexts[i];
342 if (q == m_head) {
343 break;
344 }
345 }
346 }
347 }
348 return const_iterator(q);
Shuo Chen9a43f162014-07-01 13:43:54 +0800349}
350
351template<typename T, typename Compare, typename Traits>
Shuo Chenbf2248d2014-07-12 13:47:20 +0800352typename SkipList<T, Compare, Traits>::const_iterator
353SkipList<T, Compare, Traits>::find(const T& x) const
Shuo Chen9a43f162014-07-01 13:43:54 +0800354{
Shuo Chenbf2248d2014-07-12 13:47:20 +0800355 const_iterator it = this->lower_bound(x);
356 if (it == this->end() || *it != x)
Shuo Chen9a43f162014-07-01 13:43:54 +0800357 return this->end();
358 return it;
359}
360
361template<typename T, typename Compare, typename Traits>
Shuo Chenbf2248d2014-07-12 13:47:20 +0800362std::pair<typename SkipList<T, Compare, Traits>::const_iterator, bool>
363SkipList<T, Compare, Traits>::insert(const T& x)
Shuo Chen9a43f162014-07-01 13:43:54 +0800364{
Shuo Chenbf2248d2014-07-12 13:47:20 +0800365 size_t nLevels = m_head->nexts.size();
366 // 1. find insert position
367 std::vector<NodePointer> insertPositions(nLevels);
368 NodePointer p = m_head;
369 NodePointer q = p->nexts[nLevels - 1];
370 for (int i = nLevels - 1; i >= 0; --i) {
371 q = p->nexts[i];
372 if (q != m_head) {
373 while (m_compare(q->data, x)) {
374 p = p->nexts[i];
375 q = p->nexts[i];
376 if (q == m_head) {
Shuo Chen9a43f162014-07-01 13:43:54 +0800377 break;
378 }
379 }
380 }
Shuo Chenbf2248d2014-07-12 13:47:20 +0800381 insertPositions[i] = p;
382 }
383 // 2. whether q->data == x?
384 if (q != m_head)
385 if (!m_compare(q->data, x) && !m_compare(x, q->data)) {
386 return std::pair<const_iterator, bool>(const_iterator(q), false);
387 }
388 // 3. construct new node;
389 NodePointer newNode = createNode(x);
390 // 4. pick random nLevels
391 size_t newLevel = pickRandomLevel();
392 // 5. insert the new node
393 newNode->nexts.resize(newLevel + 1);
394 newNode->prevs.resize(newLevel + 1);
395 if (newLevel > nLevels - 1) {
396 m_head->nexts.resize(newLevel + 1, m_head);
397 m_head->prevs.resize(newLevel + 1, m_head);
398 insertPositions.resize(newLevel + 1, m_head);
399 }
400 for (int i = 0; i <= static_cast<int>(newLevel); i++) {
401 newNode->nexts[i] = insertPositions[i]->nexts[i];
402 newNode->prevs[i] = insertPositions[i];
403 insertPositions[i]->nexts[i] = newNode;
404 newNode->nexts[i]->prevs[i] = newNode;
405 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800406
Shuo Chenbf2248d2014-07-12 13:47:20 +0800407 ++m_size;
408 return std::pair<const_iterator, bool>(const_iterator(newNode), true);
409}
Shuo Chen9a43f162014-07-01 13:43:54 +0800410
Shuo Chenbf2248d2014-07-12 13:47:20 +0800411template<typename T, typename Compare, typename Traits>
412typename SkipList<T, Compare, Traits>::const_iterator
413SkipList<T, Compare, Traits>::erase(typename SkipList<T, Compare, Traits>::const_iterator it)
414{
415 NodePointer eraseNode = it.node;
416 if (!empty() && eraseNode != m_head) {
417 NodePointer returnNode = eraseNode->nexts[0];
418 size_t nLevels = eraseNode->nexts.size();
419 for (int i = nLevels - 1; i >= 0; --i) {
420 eraseNode->nexts[i]->prevs[i] = eraseNode->prevs[i];
421 eraseNode->prevs[i]->nexts[i] = eraseNode->nexts[i];
422 // clear empty nLevels
423 if ((eraseNode->nexts[i] == eraseNode->prevs[i]) && i > 0) {
424 m_head->nexts.pop_back();
425 m_head->prevs.pop_back();
426 }
427 }
428 destroyNode(eraseNode);
429 --m_size;
430 return const_iterator(returnNode);
Shuo Chen9a43f162014-07-01 13:43:54 +0800431 }
432 else {
433 return end();
434 }
435}
436
437} // namespace repo
438
439#endif // REPO_STORAGE_SKIPLIST_HPP