blob: 8ef1ed98635274484d2843e6c68a0f3c50386e4e [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California.
*
* This file is part of NDN repo-ng (Next generation of NDN repository).
* See AUTHORS.md for complete list of repo-ng authors and contributors.
*
* repo-ng is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REPO_TESTS_OTHER_SKIPLIST_VECTOR_HPP
#define REPO_TESTS_OTHER_SKIPLIST_VECTOR_HPP
#include "common.hpp"
#include <random>
namespace update2 {
class SkipList32Levels25Probabilty
{
public:
static size_t
getMaxLevels()
{
return 32;
}
static double
getProbability()
{
return 0.25; // 25%
}
};
template<typename T>
struct SkipListNode
{
typedef SkipListNode<T>* SkipListNodePointer;
T data;
std::vector<SkipListNodePointer> prevs;
std::vector<SkipListNodePointer> nexts;
};
template<typename T, class Ref, class Ptr>
class SkipListIterator : public std::iterator<std::bidirectional_iterator_tag, T>
{
public:
typedef SkipListNode<T>* NodePointer;
NodePointer node;
typedef SkipListIterator<T, Ref, Ptr> Self;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef ptrdiff_t difference_type;
typedef SkipListIterator<T, const T&, const T*> const_iterator;
/// alias of const_iterator
typedef const_iterator iterator;
public:
// constructor
SkipListIterator()
{
}
explicit
SkipListIterator(NodePointer x)
: node(x)
{
}
SkipListIterator(const SkipListIterator& x)
: node(x.node)
{
}
bool
operator==(const const_iterator& x) const
{
return node == x.node;
}
bool
operator!=(const const_iterator& x) const
{
return node != x.node;
}
reference
operator*() const
{
return (*node).data;
}
pointer
operator->() const
{
return &(operator*());
}
Self&
operator++()
{
node = node->nexts.front();
return *this;
}
Self
operator++(int)
{
Self tmp = *this;
++*this;
return tmp;
}
Self&
operator--()
{
node = node->prevs.front();
return *this;
}
Self
operator--(int)
{
Self tmp = *this;
--*this;
return tmp;
}
};
/*
* @brief SkipList
*
* Examples of internal structure:
* "A <-i-> B" means A->nexts[i] = B and B->prevs[i] = A
*
* case 1: an empty skip list
* m_head <-0-> m_head
*
* case 2: a skip list with only one level and only one node
* m_head <-0-> A <-0-> m_head
*
* case 3: a skip list with three nodes, node A and B appear on one level,
* node C appears on two levels
* m_head <-1-> C <-1-> m_head
* m_head <-0-> A <-0-> B <-0-> C <-0-> m_head
*/
template<typename T, typename Compare = std::less<T>,
typename Traits = SkipList32Levels25Probabilty>
class SkipList
{
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef SkipListNode<T> Node;
typedef Node* NodePointer;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef SkipListIterator<T, const T&, const T*> const_iterator;
/// alias of const_iterator
typedef const_iterator iterator;
typedef SkipListNode<T>* SkipListNodePointer;
public:
explicit
SkipList()
{
initializeHead();
}
~SkipList()
{
clear();
delete(m_head);
}
const_iterator
begin() const
{
return const_iterator(*(*m_head).nexts.begin());
}
const_iterator
end() const
{
return const_iterator(m_head);
}
bool
empty() const
{
return *(m_head->nexts.begin()) == m_head;
}
size_t
size() const
{
return m_size;
}
const_iterator
lower_bound(const T& x) const;
const_iterator
find(const T& x) const;
std::pair<const_iterator, bool>
insert(const T& x);
const_iterator
erase(const_iterator it);
protected:
/*
* @brief initialize the node
*/
NodePointer
createNode()
{
NodePointer p = new Node;
return p;
}
/*
* @brief initialize the node with given value
* @para to be set to the value of node
*/
NodePointer
createNode(const T& x)
{
NodePointer p = new Node;
m_dataAllocator.construct(&(p->data), x);
return p;
}
/*
* @brief destructror of the node
* @para given pointer of node to be destructed
*/
void
destroyNode(NodePointer p)
{
delete(p);
}
/*
* @brief initialize the head
*/
void
initializeHead()
{
m_head = createNode();
m_head->prevs.push_back(m_head);
m_head->nexts.push_back(m_head);
m_size = 0;
}
/*
* @brief destroy all the nodes of skiplist except the head
*/
void
clear()
{
NodePointer cur = m_head->nexts[0];
while (cur != m_head) {
NodePointer tmp = cur;
cur = cur->nexts[0];
destroyNode(tmp);
}
m_head->nexts[0] = m_head;
m_head->prevs[0] = m_head;
}
/*
* @brief pick a random height for inserted skiplist entry
*/
size_t
pickRandomLevel() const
{
static std::mt19937 gen(std::random_device{}());
static std::geometric_distribution<size_t> dist(Traits::getProbability());
return std::min(dist(gen), Traits::getMaxLevels());
}
protected:
NodePointer m_head;
std::allocator<T> m_dataAllocator;
Compare m_compare;
size_t m_size;
};
template<typename T, typename Compare, typename Traits>
typename SkipList<T, Compare, Traits>::const_iterator
SkipList<T, Compare, Traits>::lower_bound(const T& x) const
{
size_t nLevels = m_head->nexts.size();
NodePointer p = m_head;
NodePointer q = p->nexts[nLevels - 1];
for (int i = nLevels - 1; i >= 0; --i) {
q = p->nexts[i];
if (q != m_head) {
while (m_compare(q->data, x)) {
p = p->nexts[i];
q = p->nexts[i];
if (q == m_head) {
break;
}
}
}
}
return const_iterator(q);
}
template<typename T, typename Compare, typename Traits>
typename SkipList<T, Compare, Traits>::const_iterator
SkipList<T, Compare, Traits>::find(const T& x) const
{
const_iterator it = this->lower_bound(x);
if (it == this->end() || *it != x)
return this->end();
return it;
}
template<typename T, typename Compare, typename Traits>
std::pair<typename SkipList<T, Compare, Traits>::const_iterator, bool>
SkipList<T, Compare, Traits>::insert(const T& x)
{
size_t nLevels = m_head->nexts.size();
// 1. find insert position
std::vector<NodePointer> insertPositions(nLevels);
NodePointer p = m_head;
NodePointer q = p->nexts[nLevels - 1];
for (int i = nLevels - 1; i >= 0; --i) {
q = p->nexts[i];
if (q != m_head) {
while (m_compare(q->data, x)) {
p = p->nexts[i];
q = p->nexts[i];
if (q == m_head) {
break;
}
}
}
insertPositions[i] = p;
}
// 2. whether q->data == x?
if (q != m_head)
if (!m_compare(q->data, x) && !m_compare(x, q->data)) {
return std::pair<const_iterator, bool>(const_iterator(q), false);
}
// 3. construct new node;
NodePointer newNode = createNode(x);
// 4. pick random nLevels
size_t newLevel = pickRandomLevel();
// 5. insert the new node
newNode->nexts.resize(newLevel + 1);
newNode->prevs.resize(newLevel + 1);
if (newLevel > nLevels - 1) {
m_head->nexts.resize(newLevel + 1, m_head);
m_head->prevs.resize(newLevel + 1, m_head);
insertPositions.resize(newLevel + 1, m_head);
}
for (size_t i = 0; i <= newLevel; i++) {
newNode->nexts[i] = insertPositions[i]->nexts[i];
newNode->prevs[i] = insertPositions[i];
insertPositions[i]->nexts[i] = newNode;
newNode->nexts[i]->prevs[i] = newNode;
}
++m_size;
return std::pair<const_iterator, bool>(const_iterator(newNode), true);
}
template<typename T, typename Compare, typename Traits>
typename SkipList<T, Compare, Traits>::const_iterator
SkipList<T, Compare, Traits>::erase(typename SkipList<T, Compare, Traits>::const_iterator it)
{
NodePointer eraseNode = it.node;
if (!empty() && eraseNode != m_head) {
NodePointer returnNode = eraseNode->nexts[0];
size_t nLevels = eraseNode->nexts.size();
for (int i = nLevels - 1; i >= 0; --i) {
eraseNode->nexts[i]->prevs[i] = eraseNode->prevs[i];
eraseNode->prevs[i]->nexts[i] = eraseNode->nexts[i];
// clear empty nLevels
if ((eraseNode->nexts[i] == eraseNode->prevs[i]) && i > 0) {
m_head->nexts.pop_back();
m_head->prevs.pop_back();
}
}
destroyNode(eraseNode);
--m_size;
return const_iterator(returnNode);
}
else {
return end();
}
}
} // namespace update2
#endif // REPO_TESTS_OTHER_SKIPLIST_VECTOR_HPP