159 lines
4.5 KiB
C
159 lines
4.5 KiB
C
|
/* 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
|