Experimental trie implementation
diff --git a/examples/trie.cc b/examples/trie.cc
new file mode 100644
index 0000000..4a70a87
--- /dev/null
+++ b/examples/trie.cc
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/ndnSIM-module.h"
+#include "../utils/trie.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("Trie");
+
+class Integer : public ns3::SimpleRefCount<Integer>
+{
+public:
+ Integer (int value) : value_ (value) {}
+
+private:
+ int value_;
+};
+
+int
+main (int argc, char *argv[])
+{
+ trie<ns3::CcnxNameComponents, Integer, smart_pointer_payload_traits<Integer> > *x =
+ new trie<ns3::CcnxNameComponents, Integer, smart_pointer_payload_traits<Integer> >("root");
+
+ ns3::CcnxNameComponents n1,n2,n3,n5;
+ n1("a")("b")("c");
+ n2("a")("c");
+ n3("b")("c");
+ n5("a")("b");
+
+ ns3::Ptr<Integer> i = ns3::Create<Integer> (1);
+ x->insert (n1, i);
+ x->insert (n2, i);
+ x->insert (n3, i);
+ x->insert (n5, i);
+
+ ns3::CcnxNameComponents n4;
+ n4("a")("c");
+
+ // std::cout << *x->find (n4).get<0> ();
+
+ x->prune ();
+ // x->find (n5).get<0> ()->erase ();
+ x->find (n1).get<0> ()->erase ();
+
+ std::cout << "digraph trie {\n";
+ std::cout << *x;
+ std::cout << "}\n";
+
+ delete x;
+
+ return 0;
+}
+
diff --git a/examples/wscript b/examples/wscript
index 1b064a3..7a49ca3 100644
--- a/examples/wscript
+++ b/examples/wscript
@@ -1,8 +1,11 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- obj = bld.create_ns3_program('ccnx-simple', ['NDNabstraction'])
+ obj = bld.create_ns3_program('ccnx-simple', ['ndnSIM'])
obj.source = 'ccnx-simple.cc'
- obj = bld.create_ns3_program('ccnx-grid', ['NDNabstraction', 'internet', 'point-to-point', 'point-to-point-layout'])
+ obj = bld.create_ns3_program('ccnx-grid', ['ndnSIM', 'point-to-point', 'point-to-point-layout'])
obj.source = 'ccnx-grid.cc'
+
+ obj = bld.create_ns3_program('trie', ['ndnSIM'])
+ obj.source = 'trie.cc'
diff --git a/model/ccnx-name-components.h b/model/ccnx-name-components.h
index 7f62851..1d8ef2a 100644
--- a/model/ccnx-name-components.h
+++ b/model/ccnx-name-components.h
@@ -46,6 +46,9 @@
class CcnxNameComponents : public SimpleRefCount<CcnxNameComponents>
{
public:
+ typedef std::list<std::string>::iterator iterator;
+ typedef std::list<std::string>::const_iterator const_iterator;
+
/**
* \brief Constructor
* Creates a prefix with zero components (can be looked as root "/")
@@ -109,6 +112,30 @@
size () const;
/**
+ * @brief Get read-write begin() iterator
+ */
+ inline iterator
+ begin ();
+
+ /**
+ * @brief Get read-only begin() iterator
+ */
+ inline const_iterator
+ begin () const;
+
+ /**
+ * @brief Get read-write end() iterator
+ */
+ inline iterator
+ end ();
+
+ /**
+ * @brief Get read-only end() iterator
+ */
+ inline const_iterator
+ end () const;
+
+ /**
* \brief Equality operator for CcnxNameComponents
*/
inline bool
@@ -119,12 +146,11 @@
*/
inline bool
operator< (const CcnxNameComponents &prefix) const;
+
+ typedef std::string partial_type;
private:
std::list<std::string> m_prefix; ///< \brief a list of strings (components)
-
- typedef std::list<std::string>::iterator iterator;
- typedef std::list<std::string>::const_iterator const_iterator;
};
/**
@@ -149,6 +175,40 @@
return m_prefix.size ();
}
+CcnxNameComponents::iterator
+CcnxNameComponents::begin ()
+{
+ return m_prefix.begin ();
+}
+
+/**
+ * @brief Get read-only begin() iterator
+ */
+CcnxNameComponents::const_iterator
+CcnxNameComponents::begin () const
+{
+ return m_prefix.begin ();
+}
+
+/**
+ * @brief Get read-write end() iterator
+ */
+CcnxNameComponents::iterator
+CcnxNameComponents::end ()
+{
+ return m_prefix.end ();
+}
+
+/**
+ * @brief Get read-only end() iterator
+ */
+CcnxNameComponents::const_iterator
+CcnxNameComponents::end () const
+{
+ return m_prefix.end ();
+}
+
+
/**
* \brief Generic constructor operator
* The object of type T will be appended to the list of components
diff --git a/utils/trie.h b/utils/trie.h
new file mode 100644
index 0000000..0e1a330
--- /dev/null
+++ b/utils/trie.h
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/ndnSIM-module.h"
+
+#include <boost/intrusive/unordered_set.hpp>
+#include <boost/functional/hash.hpp>
+
+namespace bi = boost::intrusive;
+
+/////////////////////////////////////////////////////
+// Allow customization for payload
+//
+template<typename Payload>
+struct pointer_payload_traits
+{
+ typedef Payload* pointer_type;
+ typedef const Payload* const_pointer_type;
+
+ static const Payload* empty_payload;
+};
+
+template<typename Payload>
+const Payload*
+pointer_payload_traits<Payload>::empty_payload = 0;
+
+template<typename Payload>
+struct smart_pointer_payload_traits
+{
+ typedef ns3::Ptr<Payload> pointer_type;
+ typedef ns3::Ptr<const Payload> const_pointer_type;
+
+ static const ns3::Ptr<const Payload> empty_payload;
+};
+
+template<typename Payload>
+const ns3::Ptr<const Payload>
+smart_pointer_payload_traits<Payload>::empty_payload = 0;
+
+
+////////////////////////////////////////////////////
+// forward declarations
+//
+template<typename FullKey, typename Payload, typename PayloadTraits = pointer_payload_traits<Payload> >
+class trie;
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline std::ostream&
+operator << (std::ostream &os, const trie<FullKey, Payload, PayloadTraits> &trie_node);
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+bool
+operator== (const trie<FullKey, Payload, PayloadTraits> &a, const trie<FullKey, Payload, PayloadTraits> &b);
+
+template<typename FullKey, typename Payload, typename PayloadTraits >
+std::size_t
+hash_value (const trie<FullKey, Payload, PayloadTraits> &trie_node);
+
+///////////////////////////////////////////////////
+// actual definition
+//
+
+
+template<typename FullKey,
+ typename Payload, typename PayloadTraits>
+class trie
+{
+public:
+ typedef typename FullKey::partial_type Key;
+
+ typedef trie* iterator;
+ typedef const trie* const_iterator;
+
+ inline
+ trie (const Key &key, size_t bucketSize = 10, size_t bucketIncrement = 10);
+
+ inline
+ ~trie ();
+
+ // actual entry
+ friend bool
+ operator== <> (const trie<FullKey, Payload, PayloadTraits> &a, const trie<FullKey, Payload, PayloadTraits> &b);
+
+ friend std::size_t
+ hash_value <> (const trie<FullKey, Payload, PayloadTraits> &trie_node);
+
+ inline std::pair<iterator, bool>
+ insert (const FullKey &key, typename PayloadTraits::const_pointer_type payload);
+
+ /**
+ * @brief Removes payload (if it exists) and if there are no children, prunes parents trie
+ */
+ inline void
+ erase ();
+
+ /**
+ * @brief Do exactly as erase, but without erasing the payload
+ */
+ inline void
+ prune ();
+
+ /**
+ * @brief Perform the longest prefix match
+ * @param key the key for which to perform the longest prefix match
+ *
+ * @return ->second is true if prefix in ->first is longer than key
+ */
+ inline boost::tuple<iterator, bool, iterator>
+ find (const FullKey &key);
+
+ /**
+ * @brief Find next payload of the sub-trie
+ * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
+ */
+ inline iterator
+ find ();
+
+ /**
+ * @brief Find next payload of the sub-trie satisfying the predicate
+ * @param pred predicate
+ * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
+ */
+ template<class Predicate>
+ inline iterator
+ find_if (Predicate pred);
+
+ iterator end ()
+ {
+ return 0;
+ }
+
+ const_iterator end () const
+ {
+ return 0;
+ }
+
+ // inline const_iterator
+ // find () const;
+
+private:
+ //The disposer object function
+ struct trie_delete_disposer
+ {
+ void operator() (trie *delete_this)
+ {
+ // std::cout << "Deleting " << delete_this << "\n";
+ delete delete_this;
+ }
+ };
+
+ friend
+ std::ostream&
+ operator<< < > (std::ostream &os, const trie &trie_node);
+
+private:
+ bi::unordered_set_member_hook<> member_hook_;
+
+ // necessary typedefs
+ typedef trie self_type;
+ typedef bi::member_hook< trie,
+ bi::unordered_set_member_hook< >, &trie::member_hook_ > member_hook;
+ typedef bi::unordered_set< trie, member_hook > unordered_set;
+ typedef typename unordered_set::bucket_type bucket_type;
+ typedef typename unordered_set::bucket_traits bucket_traits;
+
+ ////////////////////////////////////////////////
+ // Actual data
+ ////////////////////////////////////////////////
+
+ Key key_; ///< name component
+
+ size_t initialBucketSize_;
+ size_t bucketIncrement_;
+
+ size_t bucketSize_;
+ bucket_type *buckets_;
+ unordered_set children_;
+
+ typename PayloadTraits::const_pointer_type payload_;
+ trie *parent_; // to make cleaning effective
+};
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+trie<FullKey, Payload, PayloadTraits>::trie (const trie::Key &key, size_t bucketSize, size_t bucketIncrement)
+ : key_ (key)
+ , initialBucketSize_ (bucketSize)
+ , bucketIncrement_ (bucketIncrement)
+ , bucketSize_ (initialBucketSize_)
+ , buckets_ (new bucket_type [bucketSize_])
+ , children_ (bucket_traits (buckets_, bucketSize_))
+ , payload_ (PayloadTraits::empty_payload)
+ , parent_ (0)
+{
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+trie<FullKey, Payload, PayloadTraits>::~trie ()
+{
+ children_.clear_and_dispose (trie_delete_disposer ());
+ delete [] buckets_;
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline
+std::pair<typename trie<FullKey, Payload, PayloadTraits>::iterator, bool>
+trie<FullKey, Payload, PayloadTraits>::insert (const FullKey &key, typename PayloadTraits::const_pointer_type payload)
+{
+ trie *trieNode = this;
+
+ BOOST_FOREACH (const Key &subkey, key)
+ {
+ typename unordered_set::iterator item = trieNode->children_.find (subkey);
+ if (item == trieNode->children_.end ())
+ {
+ trie *newNode = new trie (subkey, initialBucketSize_, bucketIncrement_);
+ // std::cout << "new " << newNode << "\n";
+ newNode->parent_ = trieNode;
+
+ if (trieNode->children_.size () > trieNode->bucketSize_)
+ {
+ trieNode->bucketSize_ += trieNode->bucketIncrement_;
+ bucket_type *newBuckets = new bucket_type [trieNode->bucketSize_];
+ trieNode->children_.rehash (bucket_traits (newBuckets, trieNode->bucketSize_));
+ delete [] trieNode->buckets_;
+ trieNode->buckets_ = newBuckets;
+ }
+
+ std::pair< typename unordered_set::iterator, bool > ret =
+ trieNode->children_.insert (*newNode);
+
+ trieNode = &(*ret.first);
+ }
+ else
+ trieNode = &(*item);
+ }
+
+ if (trieNode->payload_ == 0)
+ {
+ trieNode->payload_ = payload;
+ return std::make_pair (trieNode, true);
+ }
+ else
+ return std::make_pair (trieNode, false);
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline
+boost::tuple<typename trie<FullKey, Payload, PayloadTraits>::iterator,
+ bool,
+ typename trie<FullKey, Payload, PayloadTraits>::iterator>
+trie<FullKey, Payload, PayloadTraits>::find (const FullKey &key)
+{
+ trie *trieNode = this;
+ iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
+ bool reachLast = true;
+
+ BOOST_FOREACH (const Key &subkey, key)
+ {
+ typename unordered_set::iterator item = trieNode->children_.find (subkey);
+ if (item == trieNode->children_.end ())
+ {
+ reachLast = false;
+ break;
+ }
+ else
+ {
+ trieNode = &(*item);
+
+ if (trieNode->payload_ != PayloadTraits::empty_payload)
+ foundNode = trieNode;
+ }
+ }
+
+ return boost::make_tuple (foundNode, reachLast, trieNode);
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline typename trie<FullKey, Payload, PayloadTraits>::iterator
+trie<FullKey, Payload, PayloadTraits>::find ()
+{
+ if (payload_ != PayloadTraits::empty_payload)
+ return this;
+
+ typedef trie<FullKey, Payload, PayloadTraits> trie;
+ BOOST_FOREACH (const trie &subnode, children_)
+ {
+ iterator value = subnode.find ();
+ if (value != 0)
+ return value;
+ }
+
+ return 0;
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+template<class Predicate>
+inline typename trie<FullKey, Payload, PayloadTraits>::iterator
+trie<FullKey, Payload, PayloadTraits>::find_if (Predicate pred)
+{
+ if (payload_ != PayloadTraits::empty_payload && pred (payload_))
+ return this;
+
+ typedef trie<FullKey, Payload, PayloadTraits> trie;
+ BOOST_FOREACH (const trie &subnode, children_)
+ {
+ iterator value = subnode.find ();
+ if (value != 0)
+ return value;
+ }
+
+ return 0;
+}
+
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline void
+trie<FullKey, Payload, PayloadTraits>::erase ()
+{
+ payload_ = PayloadTraits::empty_payload;
+ prune ();
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline void
+trie<FullKey, Payload, PayloadTraits>::prune ()
+{
+ if (payload_ == 0 && children_.size () == 0)
+ {
+ if (parent_ == 0) return;
+
+ trie *parent = parent_;
+ parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
+
+ parent->prune ();
+ }
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline std::ostream&
+operator << (std::ostream &os, const trie<FullKey, Payload, PayloadTraits> &trie_node)
+{
+ os << "# " << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << std::endl;
+ typedef trie<FullKey, Payload, PayloadTraits> trie;
+ BOOST_FOREACH (const trie &subnode, trie_node.children_)
+ {
+ os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << "\"]\n";
+ os << "\"" << &subnode << "\"" << " [label=\"" << subnode.key_ << ((subnode.payload_ != 0)?"*":"") << "\"]""\n";
+
+ os << "\"" << &trie_node << "\"" << " -> " << "\"" << &subnode << "\"" << "\n";
+ os << subnode;
+ }
+
+ return os;
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline bool
+operator == (const trie<FullKey, Payload, PayloadTraits> &a, const trie<FullKey, Payload, PayloadTraits> &b)
+{
+ return a.key_ == b.key_;
+}
+
+template<typename FullKey, typename Payload, typename PayloadTraits>
+inline std::size_t
+hash_value (const trie<FullKey, Payload, PayloadTraits> &trie_node)
+{
+ return boost::hash_value (trie_node.key_);
+}