blob: 0e1a3307ef107304000acd64b75110599d7b5260 [file] [log] [blame]
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2011 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
19 */
20
21#include "ns3/core-module.h"
22#include "ns3/ndnSIM-module.h"
23
24#include <boost/intrusive/unordered_set.hpp>
25#include <boost/functional/hash.hpp>
26
27namespace bi = boost::intrusive;
28
29/////////////////////////////////////////////////////
30// Allow customization for payload
31//
32template<typename Payload>
33struct pointer_payload_traits
34{
35 typedef Payload* pointer_type;
36 typedef const Payload* const_pointer_type;
37
38 static const Payload* empty_payload;
39};
40
41template<typename Payload>
42const Payload*
43pointer_payload_traits<Payload>::empty_payload = 0;
44
45template<typename Payload>
46struct smart_pointer_payload_traits
47{
48 typedef ns3::Ptr<Payload> pointer_type;
49 typedef ns3::Ptr<const Payload> const_pointer_type;
50
51 static const ns3::Ptr<const Payload> empty_payload;
52};
53
54template<typename Payload>
55const ns3::Ptr<const Payload>
56smart_pointer_payload_traits<Payload>::empty_payload = 0;
57
58
59////////////////////////////////////////////////////
60// forward declarations
61//
62template<typename FullKey, typename Payload, typename PayloadTraits = pointer_payload_traits<Payload> >
63class trie;
64
65template<typename FullKey, typename Payload, typename PayloadTraits>
66inline std::ostream&
67operator << (std::ostream &os, const trie<FullKey, Payload, PayloadTraits> &trie_node);
68
69template<typename FullKey, typename Payload, typename PayloadTraits>
70bool
71operator== (const trie<FullKey, Payload, PayloadTraits> &a, const trie<FullKey, Payload, PayloadTraits> &b);
72
73template<typename FullKey, typename Payload, typename PayloadTraits >
74std::size_t
75hash_value (const trie<FullKey, Payload, PayloadTraits> &trie_node);
76
77///////////////////////////////////////////////////
78// actual definition
79//
80
81
82template<typename FullKey,
83 typename Payload, typename PayloadTraits>
84class trie
85{
86public:
87 typedef typename FullKey::partial_type Key;
88
89 typedef trie* iterator;
90 typedef const trie* const_iterator;
91
92 inline
93 trie (const Key &key, size_t bucketSize = 10, size_t bucketIncrement = 10);
94
95 inline
96 ~trie ();
97
98 // actual entry
99 friend bool
100 operator== <> (const trie<FullKey, Payload, PayloadTraits> &a, const trie<FullKey, Payload, PayloadTraits> &b);
101
102 friend std::size_t
103 hash_value <> (const trie<FullKey, Payload, PayloadTraits> &trie_node);
104
105 inline std::pair<iterator, bool>
106 insert (const FullKey &key, typename PayloadTraits::const_pointer_type payload);
107
108 /**
109 * @brief Removes payload (if it exists) and if there are no children, prunes parents trie
110 */
111 inline void
112 erase ();
113
114 /**
115 * @brief Do exactly as erase, but without erasing the payload
116 */
117 inline void
118 prune ();
119
120 /**
121 * @brief Perform the longest prefix match
122 * @param key the key for which to perform the longest prefix match
123 *
124 * @return ->second is true if prefix in ->first is longer than key
125 */
126 inline boost::tuple<iterator, bool, iterator>
127 find (const FullKey &key);
128
129 /**
130 * @brief Find next payload of the sub-trie
131 * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
132 */
133 inline iterator
134 find ();
135
136 /**
137 * @brief Find next payload of the sub-trie satisfying the predicate
138 * @param pred predicate
139 * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
140 */
141 template<class Predicate>
142 inline iterator
143 find_if (Predicate pred);
144
145 iterator end ()
146 {
147 return 0;
148 }
149
150 const_iterator end () const
151 {
152 return 0;
153 }
154
155 // inline const_iterator
156 // find () const;
157
158private:
159 //The disposer object function
160 struct trie_delete_disposer
161 {
162 void operator() (trie *delete_this)
163 {
164 // std::cout << "Deleting " << delete_this << "\n";
165 delete delete_this;
166 }
167 };
168
169 friend
170 std::ostream&
171 operator<< < > (std::ostream &os, const trie &trie_node);
172
173private:
174 bi::unordered_set_member_hook<> member_hook_;
175
176 // necessary typedefs
177 typedef trie self_type;
178 typedef bi::member_hook< trie,
179 bi::unordered_set_member_hook< >, &trie::member_hook_ > member_hook;
180 typedef bi::unordered_set< trie, member_hook > unordered_set;
181 typedef typename unordered_set::bucket_type bucket_type;
182 typedef typename unordered_set::bucket_traits bucket_traits;
183
184 ////////////////////////////////////////////////
185 // Actual data
186 ////////////////////////////////////////////////
187
188 Key key_; ///< name component
189
190 size_t initialBucketSize_;
191 size_t bucketIncrement_;
192
193 size_t bucketSize_;
194 bucket_type *buckets_;
195 unordered_set children_;
196
197 typename PayloadTraits::const_pointer_type payload_;
198 trie *parent_; // to make cleaning effective
199};
200
201template<typename FullKey, typename Payload, typename PayloadTraits>
202trie<FullKey, Payload, PayloadTraits>::trie (const trie::Key &key, size_t bucketSize, size_t bucketIncrement)
203 : key_ (key)
204 , initialBucketSize_ (bucketSize)
205 , bucketIncrement_ (bucketIncrement)
206 , bucketSize_ (initialBucketSize_)
207 , buckets_ (new bucket_type [bucketSize_])
208 , children_ (bucket_traits (buckets_, bucketSize_))
209 , payload_ (PayloadTraits::empty_payload)
210 , parent_ (0)
211{
212}
213
214template<typename FullKey, typename Payload, typename PayloadTraits>
215trie<FullKey, Payload, PayloadTraits>::~trie ()
216{
217 children_.clear_and_dispose (trie_delete_disposer ());
218 delete [] buckets_;
219}
220
221template<typename FullKey, typename Payload, typename PayloadTraits>
222inline
223std::pair<typename trie<FullKey, Payload, PayloadTraits>::iterator, bool>
224trie<FullKey, Payload, PayloadTraits>::insert (const FullKey &key, typename PayloadTraits::const_pointer_type payload)
225{
226 trie *trieNode = this;
227
228 BOOST_FOREACH (const Key &subkey, key)
229 {
230 typename unordered_set::iterator item = trieNode->children_.find (subkey);
231 if (item == trieNode->children_.end ())
232 {
233 trie *newNode = new trie (subkey, initialBucketSize_, bucketIncrement_);
234 // std::cout << "new " << newNode << "\n";
235 newNode->parent_ = trieNode;
236
237 if (trieNode->children_.size () > trieNode->bucketSize_)
238 {
239 trieNode->bucketSize_ += trieNode->bucketIncrement_;
240 bucket_type *newBuckets = new bucket_type [trieNode->bucketSize_];
241 trieNode->children_.rehash (bucket_traits (newBuckets, trieNode->bucketSize_));
242 delete [] trieNode->buckets_;
243 trieNode->buckets_ = newBuckets;
244 }
245
246 std::pair< typename unordered_set::iterator, bool > ret =
247 trieNode->children_.insert (*newNode);
248
249 trieNode = &(*ret.first);
250 }
251 else
252 trieNode = &(*item);
253 }
254
255 if (trieNode->payload_ == 0)
256 {
257 trieNode->payload_ = payload;
258 return std::make_pair (trieNode, true);
259 }
260 else
261 return std::make_pair (trieNode, false);
262}
263
264template<typename FullKey, typename Payload, typename PayloadTraits>
265inline
266boost::tuple<typename trie<FullKey, Payload, PayloadTraits>::iterator,
267 bool,
268 typename trie<FullKey, Payload, PayloadTraits>::iterator>
269trie<FullKey, Payload, PayloadTraits>::find (const FullKey &key)
270{
271 trie *trieNode = this;
272 iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
273 bool reachLast = true;
274
275 BOOST_FOREACH (const Key &subkey, key)
276 {
277 typename unordered_set::iterator item = trieNode->children_.find (subkey);
278 if (item == trieNode->children_.end ())
279 {
280 reachLast = false;
281 break;
282 }
283 else
284 {
285 trieNode = &(*item);
286
287 if (trieNode->payload_ != PayloadTraits::empty_payload)
288 foundNode = trieNode;
289 }
290 }
291
292 return boost::make_tuple (foundNode, reachLast, trieNode);
293}
294
295template<typename FullKey, typename Payload, typename PayloadTraits>
296inline typename trie<FullKey, Payload, PayloadTraits>::iterator
297trie<FullKey, Payload, PayloadTraits>::find ()
298{
299 if (payload_ != PayloadTraits::empty_payload)
300 return this;
301
302 typedef trie<FullKey, Payload, PayloadTraits> trie;
303 BOOST_FOREACH (const trie &subnode, children_)
304 {
305 iterator value = subnode.find ();
306 if (value != 0)
307 return value;
308 }
309
310 return 0;
311}
312
313template<typename FullKey, typename Payload, typename PayloadTraits>
314template<class Predicate>
315inline typename trie<FullKey, Payload, PayloadTraits>::iterator
316trie<FullKey, Payload, PayloadTraits>::find_if (Predicate pred)
317{
318 if (payload_ != PayloadTraits::empty_payload && pred (payload_))
319 return this;
320
321 typedef trie<FullKey, Payload, PayloadTraits> trie;
322 BOOST_FOREACH (const trie &subnode, children_)
323 {
324 iterator value = subnode.find ();
325 if (value != 0)
326 return value;
327 }
328
329 return 0;
330}
331
332
333template<typename FullKey, typename Payload, typename PayloadTraits>
334inline void
335trie<FullKey, Payload, PayloadTraits>::erase ()
336{
337 payload_ = PayloadTraits::empty_payload;
338 prune ();
339}
340
341template<typename FullKey, typename Payload, typename PayloadTraits>
342inline void
343trie<FullKey, Payload, PayloadTraits>::prune ()
344{
345 if (payload_ == 0 && children_.size () == 0)
346 {
347 if (parent_ == 0) return;
348
349 trie *parent = parent_;
350 parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
351
352 parent->prune ();
353 }
354}
355
356template<typename FullKey, typename Payload, typename PayloadTraits>
357inline std::ostream&
358operator << (std::ostream &os, const trie<FullKey, Payload, PayloadTraits> &trie_node)
359{
360 os << "# " << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << std::endl;
361 typedef trie<FullKey, Payload, PayloadTraits> trie;
362 BOOST_FOREACH (const trie &subnode, trie_node.children_)
363 {
364 os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << "\"]\n";
365 os << "\"" << &subnode << "\"" << " [label=\"" << subnode.key_ << ((subnode.payload_ != 0)?"*":"") << "\"]""\n";
366
367 os << "\"" << &trie_node << "\"" << " -> " << "\"" << &subnode << "\"" << "\n";
368 os << subnode;
369 }
370
371 return os;
372}
373
374template<typename FullKey, typename Payload, typename PayloadTraits>
375inline bool
376operator == (const trie<FullKey, Payload, PayloadTraits> &a, const trie<FullKey, Payload, PayloadTraits> &b)
377{
378 return a.key_ == b.key_;
379}
380
381template<typename FullKey, typename Payload, typename PayloadTraits>
382inline std::size_t
383hash_value (const trie<FullKey, Payload, PayloadTraits> &trie_node)
384{
385 return boost::hash_value (trie_node.key_);
386}