| /* 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 |