/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef LOC_SKIP_LIST_H
#define LOC_SKIP_LIST_H
#include <stdlib.h>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
namespace loc_util {
template <typename T,
template<typename elem, typename Allocator = std::allocator<elem>> class container = list>
class SkipNode {
public:
typedef typename container<SkipNode<T, container>>::iterator NodeIterator;
int mLevel;
T mData;
NodeIterator mNextInLevel;
SkipNode(int level, T& data): mLevel(level), mData(data) {}
};
template <typename T>
class SkipList {
using NodeIterator = typename SkipNode<T>::NodeIterator;
private:
list<SkipNode<T>> mMainList;
vector<NodeIterator> mHeadVec;
vector<NodeIterator> mTailVec;
public:
SkipList(int totalLevels);
void append(T& data, int level);
void pop(int level);
void pop();
T front(int level);
int size();
void flush();
list<pair<T, int>> dump();
list<pair<T, int>> dump(int level);
};
template <typename T>
SkipList<T>::SkipList(int totalLevels): mHeadVec(totalLevels, mMainList.end()),
mTailVec(totalLevels, mMainList.end()) {}
template <typename T>
void SkipList<T>::append(T& data, int level) {
if ( level < 0 || level >= mHeadVec.size()) {
return;
}
SkipNode<T> node(level, data);
node.mNextInLevel = mMainList.end();
mMainList.push_back(node);
auto iter = --mMainList.end();
if (mHeadVec[level] == mMainList.end()) {
mHeadVec[level] = iter;
} else {
(*mTailVec[level]).mNextInLevel = iter;
}
mTailVec[level] = iter;
}
template <typename T>
void SkipList<T>::pop(int level) {
if (mHeadVec[level] == mMainList.end()) {
return;
}
if ((*mHeadVec[level]).mNextInLevel == mMainList.end()) {
mTailVec[level] = mMainList.end();
}
auto tmp_iter = (*mHeadVec[level]).mNextInLevel;
mMainList.erase(mHeadVec[level]);
mHeadVec[level] = tmp_iter;
}
template <typename T>
void SkipList<T>::pop() {
pop(mMainList.front().mLevel);
}
template <typename T>
T SkipList<T>::front(int level) {
return (*mHeadVec[level]).mData;
}
template <typename T>
int SkipList<T>::size() {
return mMainList.size();
}
template <typename T>
void SkipList<T>::flush() {
mMainList.clear();
for (int i = 0; i < mHeadVec.size(); i++) {
mHeadVec[i] = mMainList.end();
mTailVec[i] = mMainList.end();
}
}
template <typename T>
list<pair<T, int>> SkipList<T>::dump() {
list<pair<T, int>> li;
for_each(mMainList.begin(), mMainList.end(), [&](SkipNode<T> &item) {
li.push_back(make_pair(item.mData, item.mLevel));
});
return li;
}
template <typename T>
list<pair<T, int>> SkipList<T>::dump(int level) {
list<pair<T, int>> li;
auto head = mHeadVec[level];
while (head != mMainList.end()) {
li.push_back(make_pair((*head).mData, (*head).mLevel));
head = (*head).mNextInLevel;
}
return li;
}
}
#endif