blob: c19ca29a51ff5b287531c6c9b330f525bdc3365a [file] [log] [blame]
Shuo Chen9a43f162014-07-01 13:43:54 +08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento49f3a5f2017-09-23 01:36:33 -04002/*
3 * Copyright (c) 2014-2017, 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 */
Shuo Chen9a43f162014-07-01 13:43:54 +080019
WeiqiShia79c7782014-12-26 09:42:10 +080020#ifndef REPO_TESTS_OTHER_SKIPLIST_PREV_HPP
21#define REPO_TESTS_OTHER_SKIPLIST_PREV_HPP
Shuo Chen9a43f162014-07-01 13:43:54 +080022
23#include "common.hpp"
24
Davide Pesavento49f3a5f2017-09-23 01:36:33 -040025#include <random>
26
WeiqiShia79c7782014-12-26 09:42:10 +080027namespace prev {
Shuo Chen9a43f162014-07-01 13:43:54 +080028
Shuo Chenbf2248d2014-07-12 13:47:20 +080029class SkipList32Levels25Probabilty
Shuo Chen9a43f162014-07-01 13:43:54 +080030{
31public:
32 static size_t
Shuo Chenbf2248d2014-07-12 13:47:20 +080033 getMaxLevels()
Shuo Chen9a43f162014-07-01 13:43:54 +080034 {
35 return 32;
36 }
37
38 static double
39 getProbability()
40 {
Shuo Chenbf2248d2014-07-12 13:47:20 +080041 return 0.25; // 25%
Shuo Chen9a43f162014-07-01 13:43:54 +080042 }
43};
44
Shuo Chenbf2248d2014-07-12 13:47:20 +080045template<typename T>
46struct SkipListNode
47{
48 typedef SkipListNode<T>* SkipListNodePointer;
49 T data;
50 std::vector<SkipListNodePointer> prevs;
51 std::vector<SkipListNodePointer> nexts;
52};
53
54template<typename T, class Ref, class Ptr>
55class SkipListIterator : public std::iterator<std::bidirectional_iterator_tag, T>
56{
57public:
58 typedef SkipListNode<T>* NodePointer;
59 NodePointer node;
60
61 typedef SkipListIterator<T, Ref, Ptr> Self;
62 typedef T value_type;
63 typedef Ptr pointer;
64 typedef Ref reference;
65 typedef ptrdiff_t difference_type;
66 typedef SkipListIterator<T, const T&, const T*> const_iterator;
67 /// alias of const_iterator
68 typedef const_iterator iterator;
69
70public:
71 // constructor
72 SkipListIterator()
73 {
74 }
75
76 explicit
77 SkipListIterator(NodePointer x)
78 : node(x)
79 {
80 }
81
82 SkipListIterator(const SkipListIterator& x)
83 : node(x.node)
84 {
85 }
86
87 bool
88 operator==(const const_iterator& x) const
89 {
90 return node == x.node;
91 }
92
93 bool
94 operator!=(const const_iterator& x) const
95 {
96 return node != x.node;
97 }
98
99 reference
100 operator*() const
101 {
102 return (*node).data;
103 }
104
105 pointer
106 operator->() const
107 {
108 return &(operator*());
109 }
110
111 Self&
112 operator++()
113 {
114 node = node->nexts[0];
115 return *this;
116 }
117
118 Self
119 operator++(int)
120 {
121 Self tmp = *this;
122 ++*this;
123 return tmp;
124 }
125
126 Self&
127 operator--()
128 {
129 node = node->prevs[0];
130 return *this;
131 }
132
133 Self
134 operator--(int)
135 {
136 Self tmp = *this;
137 --*this;
138 return tmp;
139 }
140};
141
142/*
143 * @brief SkipList
144 *
145 * Examples of internal structure:
146 * "A <-i-> B" means A->nexts[i] = B and B->prevs[i] = A
147 *
148 * case 1: an empty skip list
149 * m_head <-0-> m_head
150 *
151 * case 2: a skip list with only one level and only one node
152 * m_head <-0-> A <-0-> m_head
153 *
154 * case 3: a skip list with three nodes, node A and B appear on one level,
155 * node C appears on two levels
156 * m_head <-1-> C <-1-> m_head
157 * m_head <-0-> A <-0-> B <-0-> C <-0-> m_head
158 */
159
Shuo Chen9a43f162014-07-01 13:43:54 +0800160template<typename T, typename Compare = std::less<T>,
Shuo Chenbf2248d2014-07-12 13:47:20 +0800161 typename Traits = SkipList32Levels25Probabilty>
Shuo Chen9a43f162014-07-01 13:43:54 +0800162class SkipList
163{
164public:
Shuo Chenbf2248d2014-07-12 13:47:20 +0800165 typedef T value_type;
166 typedef value_type* pointer;
167 typedef const value_type* const_pointer;
168 typedef value_type& reference;
169 typedef const value_type& const_reference;
170 typedef SkipListNode<T> Node;
171 typedef Node* NodePointer;
172 typedef size_t size_type;
173 typedef ptrdiff_t difference_type;
174 typedef SkipListIterator<T, const T&, const T*> const_iterator;
175 /// alias of const_iterator
176 typedef const_iterator iterator;
Shuo Chen9a43f162014-07-01 13:43:54 +0800177
178public:
179 explicit
Shuo Chenbf2248d2014-07-12 13:47:20 +0800180 SkipList()
181 {
182 initializeHead();
183 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800184
Shuo Chenbf2248d2014-07-12 13:47:20 +0800185 ~SkipList()
186 {
187 clear();
188 deallocateNode(m_head);
189 }
190
191 const_iterator
192 begin() const
193 {
194 return const_iterator(*(*m_head).nexts.begin());
195 }
196
197 const_iterator
198 end() const
199 {
200 return const_iterator(m_head);
201 }
202
203 bool
204 empty() const
205 {
206 return *(m_head->nexts.begin()) == m_head;
207 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800208
209 size_t
Shuo Chenbf2248d2014-07-12 13:47:20 +0800210 size() const
211 {
212 return m_size;
213 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800214
Shuo Chenbf2248d2014-07-12 13:47:20 +0800215 const_iterator
216 lower_bound(const T& x) const;
Shuo Chen9a43f162014-07-01 13:43:54 +0800217
Shuo Chenbf2248d2014-07-12 13:47:20 +0800218 const_iterator
219 find(const T& x) const;
Shuo Chen9a43f162014-07-01 13:43:54 +0800220
Shuo Chenbf2248d2014-07-12 13:47:20 +0800221 std::pair<const_iterator, bool>
222 insert(const T& x);
Shuo Chen9a43f162014-07-01 13:43:54 +0800223
Shuo Chenbf2248d2014-07-12 13:47:20 +0800224 const_iterator
225 erase(const_iterator it);
Shuo Chen9a43f162014-07-01 13:43:54 +0800226
Shuo Chenbf2248d2014-07-12 13:47:20 +0800227protected:
228 /*
229 * @brief allocate memory for node
230 */
231 NodePointer
232 allocateNode()
233 {
234 return m_skiplistAllocator.allocate(sizeof(Node));
235 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800236
Shuo Chenbf2248d2014-07-12 13:47:20 +0800237 /*
238 * @brief deallocate memory of node
239 */
240 void
241 deallocateNode(NodePointer p)
242 {
243 m_skiplistAllocator.deallocate(p, sizeof(Node));
244 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800245
Shuo Chenbf2248d2014-07-12 13:47:20 +0800246 /*
247 * @brief initialize the node
248 */
249 NodePointer
250 createNode()
251 {
252 NodePointer p = allocateNode();
253 Node node;
254 m_skiplistAllocator.construct(p, node);
255 return p;
256 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800257
Shuo Chenbf2248d2014-07-12 13:47:20 +0800258 /*
259 * @brief initialize the node with given value
260 * @para to be set to the value of node
261 */
262 NodePointer
263 createNode(const T& x)
264 {
265 NodePointer p = allocateNode();
266 Node node;
267 m_skiplistAllocator.construct(p, node);
268 m_dataAllocator.construct(&(p->data), x);
269 return p;
270 }
271
272 /*
273 * @brief destructror of the node
274 * @para given pointer of node to be destructed
275 */
276 void
277 destroyNode(NodePointer p)
278 {
279 m_skiplistAllocator.destroy(p);
280 deallocateNode(p);
281 }
282
283 /*
284 * @brief initialize the head
285 */
286 void
287 initializeHead()
288 {
289 m_head = createNode();
290 m_head->prevs.push_back(m_head);
291 m_head->nexts.push_back(m_head);
292 m_size = 0;
293 }
294
295 /*
296 * @brief destroy all the nodes of skiplist except the head
297 */
298 void
299 clear()
300 {
301 NodePointer cur = m_head->nexts[0];
302 while (cur != m_head) {
303 NodePointer tmp = cur;
304 cur = cur->nexts[0];
305 destroyNode(tmp);
306 }
307 m_head->nexts[0] = m_head;
308 m_head->prevs[0] = m_head;
309 }
310
311 /*
312 * @brief pick a random height for inserted skiplist entry
313 */
Shuo Chen9a43f162014-07-01 13:43:54 +0800314 size_t
Shuo Chenbf2248d2014-07-12 13:47:20 +0800315 pickRandomLevel() const
316 {
Davide Pesavento49f3a5f2017-09-23 01:36:33 -0400317 static std::mt19937 gen(std::random_device{}());
318 static std::geometric_distribution<size_t> dist(Traits::getProbability());
Shuo Chenbf2248d2014-07-12 13:47:20 +0800319 return std::min(dist(gen), Traits::getMaxLevels());
320 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800321
Shuo Chenbf2248d2014-07-12 13:47:20 +0800322protected:
323 NodePointer m_head;
324 std::allocator<Node> m_skiplistAllocator;
325 std::allocator<T> m_dataAllocator;
Shuo Chen9a43f162014-07-01 13:43:54 +0800326 Compare m_compare;
Shuo Chenbf2248d2014-07-12 13:47:20 +0800327 size_t m_size;
Shuo Chen9a43f162014-07-01 13:43:54 +0800328};
329
Shuo Chenbf2248d2014-07-12 13:47:20 +0800330
Shuo Chen9a43f162014-07-01 13:43:54 +0800331template<typename T, typename Compare, typename Traits>
Shuo Chenbf2248d2014-07-12 13:47:20 +0800332typename SkipList<T, Compare, Traits>::const_iterator
333SkipList<T, Compare, Traits>::lower_bound(const T& x) const
Shuo Chen9a43f162014-07-01 13:43:54 +0800334{
Shuo Chenbf2248d2014-07-12 13:47:20 +0800335 size_t nLevels = m_head->nexts.size();
336 NodePointer p = m_head;
337 NodePointer q = p->nexts[nLevels - 1];
338 for (int i = nLevels - 1; i >= 0; --i) {
339 q = p->nexts[i];
340 if (q != m_head) {
341 while (m_compare(q->data, x)) {
342 p = p->nexts[i];
343 q = p->nexts[i];
344 if (q == m_head) {
345 break;
346 }
347 }
348 }
349 }
350 return const_iterator(q);
Shuo Chen9a43f162014-07-01 13:43:54 +0800351}
352
353template<typename T, typename Compare, typename Traits>
Shuo Chenbf2248d2014-07-12 13:47:20 +0800354typename SkipList<T, Compare, Traits>::const_iterator
355SkipList<T, Compare, Traits>::find(const T& x) const
Shuo Chen9a43f162014-07-01 13:43:54 +0800356{
Shuo Chenbf2248d2014-07-12 13:47:20 +0800357 const_iterator it = this->lower_bound(x);
358 if (it == this->end() || *it != x)
Shuo Chen9a43f162014-07-01 13:43:54 +0800359 return this->end();
360 return it;
361}
362
363template<typename T, typename Compare, typename Traits>
Shuo Chenbf2248d2014-07-12 13:47:20 +0800364std::pair<typename SkipList<T, Compare, Traits>::const_iterator, bool>
365SkipList<T, Compare, Traits>::insert(const T& x)
Shuo Chen9a43f162014-07-01 13:43:54 +0800366{
Shuo Chenbf2248d2014-07-12 13:47:20 +0800367 size_t nLevels = m_head->nexts.size();
368 // 1. find insert position
369 std::vector<NodePointer> insertPositions(nLevels);
370 NodePointer p = m_head;
371 NodePointer q = p->nexts[nLevels - 1];
372 for (int i = nLevels - 1; i >= 0; --i) {
373 q = p->nexts[i];
374 if (q != m_head) {
375 while (m_compare(q->data, x)) {
376 p = p->nexts[i];
377 q = p->nexts[i];
378 if (q == m_head) {
Shuo Chen9a43f162014-07-01 13:43:54 +0800379 break;
380 }
381 }
382 }
Shuo Chenbf2248d2014-07-12 13:47:20 +0800383 insertPositions[i] = p;
384 }
385 // 2. whether q->data == x?
386 if (q != m_head)
387 if (!m_compare(q->data, x) && !m_compare(x, q->data)) {
388 return std::pair<const_iterator, bool>(const_iterator(q), false);
389 }
390 // 3. construct new node;
391 NodePointer newNode = createNode(x);
392 // 4. pick random nLevels
393 size_t newLevel = pickRandomLevel();
394 // 5. insert the new node
395 newNode->nexts.resize(newLevel + 1);
396 newNode->prevs.resize(newLevel + 1);
397 if (newLevel > nLevels - 1) {
398 m_head->nexts.resize(newLevel + 1, m_head);
399 m_head->prevs.resize(newLevel + 1, m_head);
400 insertPositions.resize(newLevel + 1, m_head);
401 }
Wentao Shanga8f3c402014-10-30 14:03:27 -0700402 for (size_t i = 0; i <= newLevel; i++) {
Shuo Chenbf2248d2014-07-12 13:47:20 +0800403 newNode->nexts[i] = insertPositions[i]->nexts[i];
404 newNode->prevs[i] = insertPositions[i];
405 insertPositions[i]->nexts[i] = newNode;
406 newNode->nexts[i]->prevs[i] = newNode;
407 }
Shuo Chen9a43f162014-07-01 13:43:54 +0800408
Shuo Chenbf2248d2014-07-12 13:47:20 +0800409 ++m_size;
410 return std::pair<const_iterator, bool>(const_iterator(newNode), true);
411}
Shuo Chen9a43f162014-07-01 13:43:54 +0800412
Shuo Chenbf2248d2014-07-12 13:47:20 +0800413template<typename T, typename Compare, typename Traits>
414typename SkipList<T, Compare, Traits>::const_iterator
415SkipList<T, Compare, Traits>::erase(typename SkipList<T, Compare, Traits>::const_iterator it)
416{
417 NodePointer eraseNode = it.node;
418 if (!empty() && eraseNode != m_head) {
419 NodePointer returnNode = eraseNode->nexts[0];
420 size_t nLevels = eraseNode->nexts.size();
421 for (int i = nLevels - 1; i >= 0; --i) {
422 eraseNode->nexts[i]->prevs[i] = eraseNode->prevs[i];
423 eraseNode->prevs[i]->nexts[i] = eraseNode->nexts[i];
424 // clear empty nLevels
425 if ((eraseNode->nexts[i] == eraseNode->prevs[i]) && i > 0) {
426 m_head->nexts.pop_back();
427 m_head->prevs.pop_back();
428 }
429 }
430 destroyNode(eraseNode);
431 --m_size;
432 return const_iterator(returnNode);
Shuo Chen9a43f162014-07-01 13:43:54 +0800433 }
434 else {
435 return end();
436 }
437}
438
WeiqiShia79c7782014-12-26 09:42:10 +0800439} // namespace prev
Shuo Chen9a43f162014-07-01 13:43:54 +0800440
WeiqiShia79c7782014-12-26 09:42:10 +0800441#endif // REPO_TESTS_OTHER_SKIPLIST_PREV_HPP