storage: switch index data structure from skiplist to std::set

test performance of skiplist and std::set

Change-Id: I0aa7f34e57f17a83b96fed3885d6cc6f59ad52dd
diff --git a/src/storage/index.cpp b/src/storage/index.cpp
index b141b51..2bf17ac 100644
--- a/src/storage/index.cpp
+++ b/src/storage/index.cpp
@@ -18,7 +18,6 @@
  */
 
 #include "index.hpp"
-#include "skiplist.hpp"
 
 #include <ndn-cxx/util/crypto.hpp>
 #include "ndn-cxx/security/signature-sha256-with-rsa.hpp"
@@ -70,7 +69,7 @@
   if (isFull())
     throw Error("The Index is Full. Cannot Insert Any Data!");
   Entry entry(data, id);
-  bool isInserted = m_skipList.insert(entry).second;
+  bool isInserted = m_indexContainer.insert(entry).second;
   if (isInserted)
     ++m_size;
   return isInserted;
@@ -83,7 +82,7 @@
   if (isFull())
     throw Error("The Index is Full. Cannot Insert Any Data!");
   Entry entry(fullName, keyLocatorHash, id);
-  bool isInserted = m_skipList.insert(entry).second;
+  bool isInserted = m_indexContainer.insert(entry).second;
   if (isInserted)
     ++m_size;
   return isInserted;
@@ -93,8 +92,8 @@
 Index::find(const Interest& interest) const
 {
   Name name = interest.getName();
-  IndexSkipList::const_iterator result = m_skipList.lower_bound(name);
-  if (result != m_skipList.end())
+  IndexContainer::const_iterator result = m_indexContainer.lower_bound(name);
+  if (result != m_indexContainer.end())
     {
       return selectChild(interest, result);
     }
@@ -107,8 +106,8 @@
 std::pair<int64_t,Name>
 Index::find(const Name& name) const
 {
-  IndexSkipList::const_iterator result = m_skipList.lower_bound(name);
-  if (result != m_skipList.end())
+  IndexContainer::const_iterator result = m_indexContainer.lower_bound(name);
+  if (result != m_indexContainer.end())
     {
       return findFirstEntry(name, result);
     }
@@ -122,16 +121,16 @@
 Index::hasData(const Data& data) const
 {
   Index::Entry entry(data, -1); // the id number is useless
-  IndexSkipList::const_iterator result = m_skipList.find(entry);
-  return result != m_skipList.end();
+  IndexContainer::const_iterator result = m_indexContainer.find(entry);
+  return result != m_indexContainer.end();
 
 }
 
 std::pair<int64_t,Name>
 Index::findFirstEntry(const Name& prefix,
-                      IndexSkipList::const_iterator startingPoint) const
+                      IndexContainer::const_iterator startingPoint) const
 {
-  BOOST_ASSERT(startingPoint != m_skipList.end());
+  BOOST_ASSERT(startingPoint != m_indexContainer.end());
   if (prefix.isPrefixOf(startingPoint->getName()))
     {
       return std::make_pair(startingPoint->getId(), startingPoint->getName());
@@ -146,10 +145,10 @@
 Index::erase(const Name& fullName)
 {
   Entry entry(fullName);
-  IndexSkipList::const_iterator findIterator = m_skipList.find(entry);
-  if (findIterator != m_skipList.end())
+  IndexContainer::const_iterator findIterator = m_indexContainer.find(entry);
+  if (findIterator != m_indexContainer.end())
     {
-      m_skipList.erase(findIterator);
+      m_indexContainer.erase(findIterator);
       m_size--;
       return true;
     }
@@ -167,9 +166,9 @@
 
 std::pair<int64_t,Name>
 Index::selectChild(const Interest& interest,
-                   IndexSkipList::const_iterator startingPoint) const
+                   IndexContainer::const_iterator startingPoint) const
 {
-  BOOST_ASSERT(startingPoint != m_skipList.end());
+  BOOST_ASSERT(startingPoint != m_indexContainer.end());
   bool isLeftmost = (interest.getChildSelector() <= 0);
   ndn::ConstBufferPtr hash;
   if (!interest.getPublisherPublicKeyLocator().empty())
@@ -181,8 +180,8 @@
 
   if (isLeftmost)
     {
-      for (IndexSkipList::const_iterator it = startingPoint;
-           it != m_skipList.end(); ++it)
+      for (IndexContainer::const_iterator it = startingPoint;
+           it != m_indexContainer.end(); ++it)
         {
           if (!interest.getName().isPrefixOf(it->getName()))
             return std::make_pair(0, Name());
@@ -192,15 +191,15 @@
     }
   else
     {
-      IndexSkipList::const_iterator boundary = m_skipList.lower_bound(interest.getName());
-      if (boundary == m_skipList.end() || !interest.getName().isPrefixOf(boundary->getName()))
+      IndexContainer::const_iterator boundary = m_indexContainer.lower_bound(interest.getName());
+      if (boundary == m_indexContainer.end() || !interest.getName().isPrefixOf(boundary->getName()))
         return std::make_pair(0, Name());
       Name successor = interest.getName().getSuccessor();
-      IndexSkipList::const_iterator last = interest.getName().size() == 0 ?
-                    m_skipList.end() : m_skipList.lower_bound(interest.getName().getSuccessor());
+      IndexContainer::const_iterator last = interest.getName().size() == 0 ?
+                    m_indexContainer.end() : m_indexContainer.lower_bound(interest.getName().getSuccessor());
       while (true)
         {
-          IndexSkipList::const_iterator prev = last;
+          IndexContainer::const_iterator prev = last;
           --prev;
           if (prev == boundary)
             {
@@ -212,9 +211,9 @@
               else
                 return std::make_pair(0, Name());
             }
-          IndexSkipList::const_iterator first =
-            m_skipList.lower_bound(prev->getName().getPrefix(interest.getName().size() + 1));
-          IndexSkipList::const_iterator match =
+          IndexContainer::const_iterator first =
+            m_indexContainer.lower_bound(prev->getName().getPrefix(interest.getName().size() + 1));
+          IndexContainer::const_iterator match =
                      std::find_if(first, last, bind(&matchesSimpleSelectors, interest, hash, _1));
           if (match != last)
             {
diff --git a/src/storage/index.hpp b/src/storage/index.hpp
index 90f7436..ee8eca4 100644
--- a/src/storage/index.hpp
+++ b/src/storage/index.hpp
@@ -21,8 +21,7 @@
 #define REPO_STORAGE_INDEX_HPP
 
 #include "common.hpp"
-#include "skiplist.hpp"
-#include <queue>
+#include <set>
 
 namespace repo {
 
@@ -55,7 +54,7 @@
   public:
 
     /**
-     * @brief used by skiplist to construct node
+     * @brief used by set to construct node
      */
     Entry()
     {
@@ -82,7 +81,7 @@
     /**
      *  @brief implicit construct Entry by full name
      *
-     *  Allow implicit conversion from Name for SkipList lookups by Name
+     *  Allow implicit conversion from Name for set lookups by Name
      */
     Entry(const Name& name);
 
@@ -145,7 +144,7 @@
 
 private:
 
-  typedef SkipList<Entry> IndexSkipList;
+  typedef std::set<Entry> IndexContainer;
 
 public:
   explicit
@@ -214,7 +213,7 @@
    */
   std::pair<int64_t, Name>
   selectChild(const Interest& interest,
-              IndexSkipList::const_iterator startingPoint) const;
+              IndexContainer::const_iterator startingPoint) const;
 
   /**
    *  @brief check whether the index is full
@@ -234,10 +233,10 @@
    */
   std::pair<int64_t, Name>
   findFirstEntry(const Name& prefix,
-                 IndexSkipList::const_iterator startingPoint) const;
+                 IndexContainer::const_iterator startingPoint) const;
 
 private:
-  IndexSkipList m_skipList;
+  IndexContainer m_indexContainer;
   size_t m_maxPackets;
   size_t m_size;
 };
diff --git a/src/storage/skiplist.hpp b/tests/other/skiplist-list.hpp
similarity index 70%
copy from src/storage/skiplist.hpp
copy to tests/other/skiplist-list.hpp
index e6dd6a0..72d1dda 100644
--- a/src/storage/skiplist.hpp
+++ b/tests/other/skiplist-list.hpp
@@ -17,12 +17,11 @@
 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
 */
 
-#ifndef REPO_STORAGE_SKIPLIST_HPP
-#define REPO_STORAGE_SKIPLIST_HPP
-
+#ifndef REPO_TESTS_OTHER_SKIPLIST_LIST_HPP
+#define REPO_TESTS_OTHER_SKIPLIST_LIST_HPP
 #include "common.hpp"
 
-namespace repo {
+namespace update1 {
 
 class SkipList32Levels25Probabilty
 {
@@ -45,8 +44,8 @@
 {
   typedef SkipListNode<T>* SkipListNodePointer;
   T data;
-  std::vector<SkipListNodePointer> prevs;
-  std::vector<SkipListNodePointer> nexts;
+  std::list<SkipListNodePointer> prevs;
+  std::list<SkipListNodePointer> nexts;
 };
 
 template<typename T, class Ref, class Ptr>
@@ -109,7 +108,7 @@
   Self&
   operator++()
   {
-    node = node->nexts[0];
+    node = node->nexts.front();
     return *this;
   }
 
@@ -124,7 +123,7 @@
   Self&
   operator--()
   {
-    node = node->prevs[0];
+    node = node->prevs.front();
     return *this;
   }
 
@@ -172,6 +171,7 @@
   typedef SkipListIterator<T, const T&, const T*> const_iterator;
   /// alias of const_iterator
   typedef const_iterator iterator;
+  typedef SkipListNode<T>* SkipListNodePointer;
 
 public:
   explicit
@@ -183,7 +183,7 @@
   ~SkipList()
   {
     clear();
-    deallocateNode(m_head);
+    delete(m_head);
   }
 
   const_iterator
@@ -223,23 +223,6 @@
   erase(const_iterator it);
 
 protected:
-  /*
-   * @brief allocate memory for node
-   */
-  NodePointer
-  allocateNode()
-  {
-    return m_skiplistAllocator.allocate(sizeof(Node));
-  }
-
-  /*
-   * @brief deallocate memory of node
-   */
-  void
-  deallocateNode(NodePointer p)
-  {
-    m_skiplistAllocator.deallocate(p, sizeof(Node));
-  }
 
   /*
    * @brief initialize the node
@@ -247,9 +230,7 @@
   NodePointer
   createNode()
   {
-    NodePointer p = allocateNode();
-    Node node;
-    m_skiplistAllocator.construct(p, node);
+    NodePointer p = new Node;
     return p;
   }
 
@@ -260,9 +241,7 @@
   NodePointer
   createNode(const T& x)
   {
-    NodePointer p = allocateNode();
-    Node node;
-    m_skiplistAllocator.construct(p, node);
+    NodePointer p = new Node;
     m_dataAllocator.construct(&(p->data), x);
     return p;
   }
@@ -274,8 +253,7 @@
   void
   destroyNode(NodePointer p)
   {
-    m_skiplistAllocator.destroy(p);
-    deallocateNode(p);
+    delete(p);
   }
 
   /*
@@ -296,14 +274,14 @@
   void
   clear()
   {
-    NodePointer cur = m_head->nexts[0];
+    NodePointer cur = m_head->nexts.front();
     while (cur != m_head) {
       NodePointer tmp = cur;
-      cur = cur->nexts[0];
+      cur = cur->nexts.front();
       destroyNode(tmp);
     }
-    m_head->nexts[0] = m_head;
-    m_head->prevs[0] = m_head;
+    m_head->nexts.front() = m_head;
+    m_head->prevs.front() = m_head;
   }
 
   /*
@@ -319,7 +297,6 @@
 
 protected:
   NodePointer m_head;
-  std::allocator<Node> m_skiplistAllocator;
   std::allocator<T> m_dataAllocator;
   Compare m_compare;
   size_t m_size;
@@ -332,13 +309,21 @@
 {
   size_t nLevels = m_head->nexts.size();
   NodePointer p = m_head;
-  NodePointer q = p->nexts[nLevels - 1];
+  NodePointer q = p->nexts.back();
   for (int i = nLevels - 1; i >= 0; --i) {
-    q = p->nexts[i];
+    typename std::list<SkipListNodePointer>::iterator it_p = p->nexts.begin();
+    for (int j = 0; j < i; j++) {
+      it_p++;
+    }
+    q = *it_p;
     if (q != m_head) {
       while (m_compare(q->data, x)) {
-        p = p->nexts[i];
-        q = p->nexts[i];
+        p = *it_p;
+        it_p = p->nexts.begin();
+        for (int j = 0; j < i; j++) {
+          it_p++;
+        }
+        q = *it_p;
         if (q == m_head) {
           break;
         }
@@ -366,13 +351,21 @@
   // 1. find insert position
   std::vector<NodePointer> insertPositions(nLevels);
   NodePointer p = m_head;
-  NodePointer q = p->nexts[nLevels - 1];
+  NodePointer q = p->nexts.back();
   for (int i = nLevels - 1; i >= 0; --i) {
-    q = p->nexts[i];
+    typename std::list<SkipListNodePointer>::iterator it_p = p->nexts.begin();
+    for (int j = 0; j < i; j++) {
+      it_p++;
+    }
+    q = *it_p;
     if (q != m_head) {
       while (m_compare(q->data, x)) {
-        p = p->nexts[i];
-        q = p->nexts[i];
+        p = *it_p;
+        it_p = p->nexts.begin();
+        for (int j = 0; j < i; j++) {
+          it_p++;
+        }
+        q = *it_p;
         if (q == m_head) {
           break;
         }
@@ -398,10 +391,36 @@
     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;
+    typename std::list<SkipListNodePointer>::iterator it_newNode_next = newNode->nexts.begin();
+    for (size_t j = 0; j < i; j++) {
+      it_newNode_next++;
+    }
+    typename std::list<SkipListNodePointer>::iterator it_insert_next = insertPositions[i]->nexts.begin();
+    for (size_t j = 0; j < i; j++) {
+      it_insert_next++;
+    }
+    *it_newNode_next = *it_insert_next;
+
+    typename std::list<SkipListNodePointer>::iterator it_newNode_prev = newNode->prevs.begin();
+    for (size_t j = 0; j < i; j++) {
+      it_newNode_prev++;
+    }
+    *it_newNode_prev = insertPositions[i];
+
+    it_insert_next = insertPositions[i]->nexts.begin();
+    for (size_t j = 0; j < i; j++) {
+      it_insert_next++;
+    }
+    *it_insert_next = newNode;
+    it_newNode_next = newNode->nexts.begin();
+    for (size_t j = 0; j < i; j++) {
+      it_newNode_next++;
+    }
+    typename std::list<SkipListNodePointer>::iterator it_newNode_next_prev = (*it_newNode_next)->prevs.begin();
+    for (size_t j = 0; j < i; j++) {
+      it_newNode_next_prev++;
+    }
+    *it_newNode_next_prev = newNode;
   }
 
   ++m_size;
@@ -414,13 +433,33 @@
 {
   NodePointer eraseNode = it.node;
   if (!empty() && eraseNode != m_head) {
-    NodePointer returnNode = eraseNode->nexts[0];
+    NodePointer returnNode = eraseNode->nexts.front();
     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];
+      typename std::list<SkipListNodePointer>::iterator it_erase_next = eraseNode->nexts.begin();
+      for (int j = 0; j < i; j++) {
+        it_erase_next++;
+      }
+
+      typename std::list<SkipListNodePointer>::iterator it_erase_next_prev = (*it_erase_next)->prevs.begin();
+      for (int j = 0; j < i; j++) {
+        it_erase_next_prev++;
+      }
+
+      typename std::list<SkipListNodePointer>::iterator it_erase_prev = eraseNode->prevs.begin();
+      for (int j = 0; j < i; j++) {
+        it_erase_prev++;
+      }
+      *it_erase_next_prev = *it_erase_prev;
+
+      typename std::list<SkipListNodePointer>::iterator it_erase_prev_next = (*it_erase_prev)->nexts.begin();
+      for (int j = 0; j < i; j++) {
+        it_erase_prev_next++;
+      }
+
+      *it_erase_prev_next = *it_erase_next;
       // clear empty nLevels
-      if ((eraseNode->nexts[i] == eraseNode->prevs[i]) && i > 0) {
+      if ((*it_erase_next == *it_erase_prev) && i > 0) {
         m_head->nexts.pop_back();
         m_head->prevs.pop_back();
       }
@@ -434,6 +473,6 @@
   }
 }
 
-} // namespace repo
+} //end namespace update1
 
-#endif // REPO_STORAGE_SKIPLIST_HPP
+#endif // REPO_TESTS_UNIT_SKIPLIST_LIST_HPP
diff --git a/src/storage/skiplist.hpp b/tests/other/skiplist-prev.hpp
similarity index 97%
rename from src/storage/skiplist.hpp
rename to tests/other/skiplist-prev.hpp
index e6dd6a0..1bb416d 100644
--- a/src/storage/skiplist.hpp
+++ b/tests/other/skiplist-prev.hpp
@@ -17,12 +17,12 @@
 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
 */
 
-#ifndef REPO_STORAGE_SKIPLIST_HPP
-#define REPO_STORAGE_SKIPLIST_HPP
+#ifndef REPO_TESTS_OTHER_SKIPLIST_PREV_HPP
+#define REPO_TESTS_OTHER_SKIPLIST_PREV_HPP
 
 #include "common.hpp"
 
-namespace repo {
+namespace prev {
 
 class SkipList32Levels25Probabilty
 {
@@ -434,6 +434,6 @@
   }
 }
 
-} // namespace repo
+} // namespace prev
 
-#endif // REPO_STORAGE_SKIPLIST_HPP
+#endif // REPO_TESTS_OTHER_SKIPLIST_PREV_HPP
diff --git a/tests/other/skiplist-smoketest.cpp b/tests/other/skiplist-smoketest.cpp
new file mode 100644
index 0000000..645c7a2
--- /dev/null
+++ b/tests/other/skiplist-smoketest.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  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/>.
+ */
+
+#include "skiplist-list.hpp" // This skiplist is updated by weiqi.
+                              // The internal structure of skiplist node is std::list
+
+#include "skiplist-vector.hpp" // This skiplist is revised is revised based on the version above
+                               // The internal structure of skiplist node is std::vector
+
+#include "skiplist-prev.hpp" // This skiplist is that of previous commit
+
+#include <iostream>
+#include <set>
+
+using namespace ndn::time;
+
+namespace repo {
+namespace tests {
+
+void
+testSkipList()
+{
+  typedef update1::SkipList<int, std::greater<int> > IntGtContainer;
+  IntGtContainer sl;
+  steady_clock::TimePoint start = steady_clock::now();
+  for (int i = 0; i < 100000; ++i) {
+    sl.insert(i);
+  }
+  milliseconds duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  start = steady_clock::now();
+  std::cout << "SkipList-list insert 100000 integers cost " << duration.count() << "ms" << std::endl;
+  for (int i = 0; i< 100000; ++i) {
+    sl.lower_bound(i);
+  }
+  duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  std::cout << "SkipList-list lower_bound 100000 integers cost " << duration.count() << "ms" << std::endl;
+}
+
+void
+testSkipVector()
+{
+  typedef update2::SkipList<int, std::greater<int> > IntGtContainer;
+  IntGtContainer container;
+  steady_clock::TimePoint start = steady_clock::now();
+  for (int i = 0; i < 100000; ++i) {
+    container.insert(i);
+  }
+  milliseconds duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  start = steady_clock::now();
+  std::cout << "Skiplist-vector insert 100000 integers cost " << duration.count() << "ms" << std::endl;
+  for (int i = 0; i< 100000; ++i) {
+    container.lower_bound(i);
+  }
+  duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  std::cout << "Skiplist-vector lower_bound 100000 integers cost " << duration.count() << "ms" << std::endl;
+}
+
+void
+testSkipPrev()
+{
+  typedef prev::SkipList<int, std::greater<int> > IntGtContainer;
+  IntGtContainer container;
+  steady_clock::TimePoint start = steady_clock::now();
+  for (int i = 0; i < 100000; ++i) {
+    container.insert(i);
+  }
+  milliseconds duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  start = steady_clock::now();
+  std::cout << "Skiplist-prev insert 100000 integers cost " << duration.count() << "ms" << std::endl;
+  for (int i = 0; i< 100000; ++i) {
+    container.lower_bound(i);
+  }
+  duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  std::cout << "Skiplist-prev lower_bound 100000 integers cost " << duration.count() << "ms" << std::endl;
+}
+
+void
+testSet()
+{
+  typedef std::set<int, std::greater<int> > IntGtContainer;
+  IntGtContainer container;
+  steady_clock::TimePoint start = steady_clock::now();
+  for (int i = 0; i < 100000; ++i) {
+    container.insert(i);
+  }
+  milliseconds duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  start = steady_clock::now();
+  std::cout << "Set insert 100000 integers cost " << duration.count() << "ms" << std::endl;
+  for (int i = 0; i< 100000; ++i) {
+    container.lower_bound(i);
+  }
+  duration = duration_cast<milliseconds>(steady_clock::now() - start);
+  std::cout << "Set lower_bound 100000 integers cost " << duration.count() << "ms" << std::endl;
+}
+
+void runTestCases() {
+  testSkipList();
+  testSkipVector();
+  testSkipPrev();
+  testSet();
+}
+
+} // namespace tests
+} // namespace repo
+
+int
+main(int argc, char** argv)
+{
+  repo::tests::runTestCases();
+
+  return 0;
+}
\ No newline at end of file
diff --git a/src/storage/skiplist.hpp b/tests/other/skiplist-vector.hpp
similarity index 90%
copy from src/storage/skiplist.hpp
copy to tests/other/skiplist-vector.hpp
index e6dd6a0..6079dd3 100644
--- a/src/storage/skiplist.hpp
+++ b/tests/other/skiplist-vector.hpp
@@ -17,12 +17,11 @@
 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
 */
 
-#ifndef REPO_STORAGE_SKIPLIST_HPP
-#define REPO_STORAGE_SKIPLIST_HPP
-
+#ifndef REPO_TESTS_OTHER_SKIPLIST_VECTOR_HPP
+#define REPO_TESTS_OTHER_SKIPLIST_VECTOR_HPP
 #include "common.hpp"
 
-namespace repo {
+namespace update2 {
 
 class SkipList32Levels25Probabilty
 {
@@ -109,7 +108,7 @@
   Self&
   operator++()
   {
-    node = node->nexts[0];
+    node = node->nexts.front();
     return *this;
   }
 
@@ -124,7 +123,7 @@
   Self&
   operator--()
   {
-    node = node->prevs[0];
+    node = node->prevs.front();
     return *this;
   }
 
@@ -172,6 +171,7 @@
   typedef SkipListIterator<T, const T&, const T*> const_iterator;
   /// alias of const_iterator
   typedef const_iterator iterator;
+  typedef SkipListNode<T>* SkipListNodePointer;
 
 public:
   explicit
@@ -183,7 +183,7 @@
   ~SkipList()
   {
     clear();
-    deallocateNode(m_head);
+    delete(m_head);
   }
 
   const_iterator
@@ -223,23 +223,6 @@
   erase(const_iterator it);
 
 protected:
-  /*
-   * @brief allocate memory for node
-   */
-  NodePointer
-  allocateNode()
-  {
-    return m_skiplistAllocator.allocate(sizeof(Node));
-  }
-
-  /*
-   * @brief deallocate memory of node
-   */
-  void
-  deallocateNode(NodePointer p)
-  {
-    m_skiplistAllocator.deallocate(p, sizeof(Node));
-  }
 
   /*
    * @brief initialize the node
@@ -247,9 +230,7 @@
   NodePointer
   createNode()
   {
-    NodePointer p = allocateNode();
-    Node node;
-    m_skiplistAllocator.construct(p, node);
+    NodePointer p = new Node;
     return p;
   }
 
@@ -260,9 +241,7 @@
   NodePointer
   createNode(const T& x)
   {
-    NodePointer p = allocateNode();
-    Node node;
-    m_skiplistAllocator.construct(p, node);
+    NodePointer p = new Node;
     m_dataAllocator.construct(&(p->data), x);
     return p;
   }
@@ -274,8 +253,7 @@
   void
   destroyNode(NodePointer p)
   {
-    m_skiplistAllocator.destroy(p);
-    deallocateNode(p);
+    delete(p);
   }
 
   /*
@@ -319,7 +297,6 @@
 
 protected:
   NodePointer m_head;
-  std::allocator<Node> m_skiplistAllocator;
   std::allocator<T> m_dataAllocator;
   Compare m_compare;
   size_t m_size;
@@ -432,8 +409,9 @@
   else {
     return end();
   }
+
 }
 
-} // namespace repo
+} //end namespace update2
 
-#endif // REPO_STORAGE_SKIPLIST_HPP
+#endif // REPO_TESTS_OTHER_SKIPLIST_VECTOR_HPP
diff --git a/tests/other/wscript b/tests/other/wscript
new file mode 100644
index 0000000..6bb9fb6
--- /dev/null
+++ b/tests/other/wscript
@@ -0,0 +1,10 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+top = '../..'
+
+def build(bld):
+    bld.program(target="../../skiplist-smoketest",
+                source="skiplist-smoketest.cpp",
+                use='ndn-repo-objects',
+                install_path=None,
+                )
\ No newline at end of file
diff --git a/tests/unit/skiplist.cpp b/tests/unit/skiplist.cpp
deleted file mode 100644
index 5bbb0ff..0000000
--- a/tests/unit/skiplist.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  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/>.
- */
-
-#include "storage/skiplist.hpp"
-
-#include "../sqlite-fixture.hpp"
-#include "../dataset-fixtures.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/concept_check.hpp>
-#include <iostream>
-
-namespace repo {
-namespace tests {
-
-BOOST_AUTO_TEST_SUITE(SkipList)
-
-template<class Dataset>
-class Fixture : public Dataset
-{
-};
-
-BOOST_AUTO_TEST_CASE(Correctness)
-{
-  typedef repo::SkipList<int, std::greater<int> > IntGtSkipList;
-  IntGtSkipList sl;
-  BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<IntGtSkipList::iterator>));
-
-  // initial state
-  BOOST_CHECK_EQUAL(sl.size(), 0);
-  BOOST_CHECK(sl.begin() == sl.end());
-  BOOST_CHECK(sl.lower_bound(10) == sl.end());
-
-  // initial contents
-  sl.insert(10);
-  sl.insert(20);
-  sl.insert(30);
-  BOOST_CHECK_EQUAL(sl.size(), 3);
-  // contents: [30,20,10]
-
-  // iterators
-  IntGtSkipList::iterator it1 = sl.begin();
-  IntGtSkipList::iterator it2 = sl.end();
-  --it2;
-  BOOST_CHECK_EQUAL(*it1, 30);
-  BOOST_CHECK_EQUAL(*it2, 10);
-  ++it1;
-  BOOST_CHECK_EQUAL(*it1, 20);
-  IntGtSkipList::iterator it3 = it1;
-  ++it1;
-  BOOST_CHECK(it2 == it1);
-  BOOST_CHECK_EQUAL(*it3, 20);
-
-  // lower_bound
-  IntGtSkipList::iterator found = sl.lower_bound(35);
-  BOOST_CHECK(found == sl.begin());
-  BOOST_CHECK_EQUAL(*found, 30);
-  found = sl.lower_bound(30);
-  BOOST_CHECK_EQUAL(*found, 30);
-  found = sl.lower_bound(25);
-  BOOST_CHECK_EQUAL(*found, 20);
-  found = sl.lower_bound(20);
-  BOOST_CHECK_EQUAL(*found, 20);
-  found = sl.lower_bound(15);
-  BOOST_CHECK_EQUAL(*found, 10);
-  found = sl.lower_bound(10);
-  BOOST_CHECK_EQUAL(*found, 10);
-  found = sl.lower_bound(5);
-  BOOST_CHECK(found == sl.end());
-
-  // insert duplicate
-  std::pair<IntGtSkipList::iterator, bool> insertRes = sl.insert(10);
-  BOOST_CHECK_EQUAL(insertRes.second, false);
-  BOOST_CHECK_EQUAL(*(insertRes.first), 10);
-  BOOST_CHECK_EQUAL(sl.size(), 3);
-  insertRes = sl.insert(20);
-  BOOST_CHECK_EQUAL(insertRes.second, false);
-  BOOST_CHECK_EQUAL(*(insertRes.first), 20);
-  BOOST_CHECK_EQUAL(sl.size(), 3);
-  insertRes = sl.insert(30);
-  BOOST_CHECK_EQUAL(insertRes.second, false);
-  BOOST_CHECK_EQUAL(*(insertRes.first), 30);
-  BOOST_CHECK_EQUAL(sl.size(), 3);
-
-  // insert non-duplicate
-  insertRes = sl.insert(5);
-  BOOST_CHECK_EQUAL(insertRes.second, true);
-  BOOST_CHECK_EQUAL(*(insertRes.first), 5);
-  BOOST_CHECK_EQUAL(sl.size(), 4);
-  insertRes = sl.insert(35);
-  BOOST_CHECK_EQUAL(insertRes.second, true);
-  BOOST_CHECK_EQUAL(*(insertRes.first), 35);
-  BOOST_CHECK_EQUAL(sl.size(), 5);
-  // contents: [35,30,20,10,5]
-
-  // erase
-  it1 = sl.erase(sl.begin());
-  // contents: [30,20,10,5]
-  BOOST_CHECK_EQUAL(*it1, 30);
-  BOOST_CHECK_EQUAL(sl.size(), 4);
-  it2 = sl.end();
-  --it2;
-  it1 = sl.erase(it2);
-  // contents: [30,20,10]
-  BOOST_CHECK(it1 == sl.end());
-  BOOST_CHECK_EQUAL(sl.size(), 3);
-  it2 = sl.lower_bound(20);
-  it1 = sl.erase(it2);
-  // contents: [30,10]
-  BOOST_CHECK_EQUAL(*it1, 10);
-  BOOST_CHECK_EQUAL(sl.size(), 2);
-  it3 = it1;
-  --it1;
-  BOOST_CHECK(it1 == sl.begin());
-  BOOST_CHECK_EQUAL(*it1, 30);
-  ++it3;
-  BOOST_CHECK(it3 == sl.end());
-}
-
-class Item : public ndn::Name
-{
-public:
-  explicit
-  Item(const ndn::Name& name = "")
-    : ndn::Name(name)
-    , randomValue(ndn::random::generateWord64())
-  {
-  }
-
-public:
-  uint64_t randomValue;
-};
-
-BOOST_FIXTURE_TEST_CASE_TEMPLATE(Bulk, T, CommonDatasets, Fixture<T>)
-{
-  BOOST_TEST_MESSAGE(T::getName());
-  typedef repo::SkipList<Item, std::less<Item> > SkipList;
-  SkipList skipList;
-
-  std::vector<Item> items;
-  std::set<ndn::Name> names;
-  for (typename T::DataContainer::iterator i = this->data.begin();
-       i != this->data.end(); ++i) {
-    std::pair<std::set<ndn::Name>::iterator, bool> ret = names.insert((*i)->getName());
-    if (ret.second) {
-      items.push_back(Item((*i)->getName()));
-    }
-  }
-
-  // Insert
-  for (std::vector<Item>::iterator i = items.begin(); i != items.end(); ++i) {
-    skipList.insert(*i);
-  }
-
-  BOOST_CHECK_EQUAL(items.size(), skipList.size());
-
-  // Randomize items
-  std::random_shuffle(items.begin(), items.end());
-
-  // Find items and check if the right item is found
-  for (std::vector<Item>::iterator i = items.begin(); i != items.end(); ++i) {
-    SkipList::iterator item = skipList.find(*i);
-    BOOST_CHECK(item != skipList.end());
-
-    BOOST_CHECK_EQUAL(static_cast<const Name&>(*item), static_cast<const Name&>(*i));
-    BOOST_CHECK_EQUAL(item->randomValue, i->randomValue);
-  }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace repo
diff --git a/wscript b/wscript
index 537a3e9..02be7f5 100644
--- a/wscript
+++ b/wscript
@@ -68,6 +68,7 @@
 
     # Tests
     bld.recurse('tests')
+    bld.recurse("tests/other")
 
     # Tools
     bld.recurse('tools')