blob: edc8a1b1b2648f2cc8b6c494a389d24222f60d7a [file] [log] [blame]
Jeff Thompsonfa306642013-06-17 15:06:57 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Alexander Afanasyev
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
9 */
10
11#ifndef NDN_TRIE_TRIE_H_
12#define NDN_TRIE_TRIE_H_
13
14#include <boost/intrusive/unordered_set.hpp>
15#include <boost/intrusive/list.hpp>
16#include <boost/intrusive/set.hpp>
17#include <boost/functional/hash.hpp>
18#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
19#include <boost/tuple/tuple.hpp>
20#include <boost/foreach.hpp>
21#include <boost/mpl/if.hpp>
22
23#include "payload-traits/pointer.h"
24#include "payload-traits/ptr.h"
25
26namespace ndn {
27namespace trie {
28
29////////////////////////////////////////////////////
30// forward declarations
31//
32template<typename FullKey,
33 typename PayloadTraits,
34 typename PolicyHook >
35class trie;
36
37template<typename FullKey, typename PayloadTraits, typename PolicyHook>
38inline std::ostream&
39operator << (std::ostream &os,
40 const trie<FullKey, PayloadTraits, PolicyHook> &trie_node);
41
42template<typename FullKey, typename PayloadTraits, typename PolicyHook>
43bool
44operator== (const trie<FullKey, PayloadTraits, PolicyHook> &a,
45 const trie<FullKey, PayloadTraits, PolicyHook> &b);
46
47template<typename FullKey, typename PayloadTraits, typename PolicyHook >
48std::size_t
49hash_value (const trie<FullKey, PayloadTraits, PolicyHook> &trie_node);
50
51///////////////////////////////////////////////////
52// actual definition
53//
54template<class T, class NonConstT>
55class trie_iterator;
56
57template<class T>
58class trie_point_iterator;
59
60template<typename FullKey,
61 typename PayloadTraits,
62 typename PolicyHook >
63class trie
64{
65public:
66 typedef typename FullKey::partial_type Key;
67
68 typedef trie* iterator;
69 typedef const trie* const_iterator;
70
71 typedef trie_iterator<trie, trie> recursive_iterator;
72 typedef trie_iterator<const trie, trie> const_recursive_iterator;
73
74 typedef trie_point_iterator<trie> point_iterator;
75 typedef trie_point_iterator<const trie> const_point_iterator;
76
77 typedef PayloadTraits payload_traits;
78
79 inline
80 trie (const Key &key, size_t bucketSize = 10, size_t bucketIncrement = 10)
81 : key_ (key)
82 , initialBucketSize_ (bucketSize)
83 , bucketIncrement_ (bucketIncrement)
84 , bucketSize_ (initialBucketSize_)
85 , buckets_ (new bucket_type [bucketSize_]) //cannot use normal pointer, because lifetime of buckets should be larger than lifetime of the container
86 , children_ (bucket_traits (buckets_.get (), bucketSize_))
87 , payload_ (PayloadTraits::empty_payload)
88 , parent_ (0)
89 {
90 }
91
92 inline
93 ~trie ()
94 {
95 payload_ = PayloadTraits::empty_payload; // necessary for smart pointers...
96 children_.clear_and_dispose (trie_delete_disposer ());
97 }
98
99 void
100 clear ()
101 {
102 children_.clear_and_dispose (trie_delete_disposer ());
103 }
104
105 template<class Predicate>
106 void
107 clear_if (Predicate cond)
108 {
109 recursive_iterator trieNode (this);
110 recursive_iterator end (0);
111
112 while (trieNode != end)
113 {
114 if (cond (*trieNode))
115 {
116 trieNode = recursive_iterator (trieNode->erase ());
117 }
118 trieNode ++;
119 }
120 }
121
122 // actual entry
123 friend bool
124 operator== <> (const trie<FullKey, PayloadTraits, PolicyHook> &a,
125 const trie<FullKey, PayloadTraits, PolicyHook> &b);
126
127 friend std::size_t
128 hash_value <> (const trie<FullKey, PayloadTraits, PolicyHook> &trie_node);
129
130 inline std::pair<iterator, bool>
131 insert (const FullKey &key,
132 typename PayloadTraits::insert_type payload)
133 {
134 trie *trieNode = this;
135
136 BOOST_FOREACH (const Key &subkey, key)
137 {
138 typename unordered_set::iterator item = trieNode->children_.find (subkey);
139 if (item == trieNode->children_.end ())
140 {
141 trie *newNode = new trie (subkey, initialBucketSize_, bucketIncrement_);
142 // std::cout << "new " << newNode << "\n";
143 newNode->parent_ = trieNode;
144
145 if (trieNode->children_.size () >= trieNode->bucketSize_)
146 {
147 trieNode->bucketSize_ += trieNode->bucketIncrement_;
148 trieNode->bucketIncrement_ *= 2; // increase bucketIncrement exponentially
149
150 buckets_array newBuckets (new bucket_type [trieNode->bucketSize_]);
151 trieNode->children_.rehash (bucket_traits (newBuckets.get (), trieNode->bucketSize_));
152 trieNode->buckets_.swap (newBuckets);
153 }
154
155 std::pair< typename unordered_set::iterator, bool > ret =
156 trieNode->children_.insert (*newNode);
157
158 trieNode = &(*ret.first);
159 }
160 else
161 trieNode = &(*item);
162 }
163
164 if (trieNode->payload_ == PayloadTraits::empty_payload)
165 {
166 trieNode->payload_ = payload;
167 return std::make_pair (trieNode, true);
168 }
169 else
170 return std::make_pair (trieNode, false);
171 }
172
173 /**
174 * @brief Removes payload (if it exists) and if there are no children, prunes parents trie
175 */
176 inline iterator
177 erase ()
178 {
179 payload_ = PayloadTraits::empty_payload;
180 return prune ();
181 }
182
183 /**
184 * @brief Do exactly as erase, but without erasing the payload
185 */
186 inline iterator
187 prune ()
188 {
189 if (payload_ == PayloadTraits::empty_payload &&
190 children_.size () == 0)
191 {
192 if (parent_ == 0) return this;
193
194 trie *parent = parent_;
195 parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
196
197 return parent->prune ();
198 }
199 return this;
200 }
201
202 /**
203 * @brief Perform prune of the node, but without attempting to parent of the node
204 */
205 inline void
206 prune_node ()
207 {
208 if (payload_ == PayloadTraits::empty_payload &&
209 children_.size () == 0)
210 {
211 if (parent_ == 0) return;
212
213 trie *parent = parent_;
214 parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
215 }
216 }
217
218 // inline boost::tuple<const iterator, bool, const iterator>
219 // find (const FullKey &key) const
220 // {
221 // return const_cast<trie*> (this)->find (key);
222 // }
223
224 /**
225 * @brief Perform the longest prefix match
226 * @param key the key for which to perform the longest prefix match
227 *
228 * @return ->second is true if prefix in ->first is longer than key
229 */
230 inline boost::tuple<iterator, bool, iterator>
231 find (const FullKey &key)
232 {
233 trie *trieNode = this;
234 iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
235 bool reachLast = true;
236
237 BOOST_FOREACH (const Key &subkey, key)
238 {
239 typename unordered_set::iterator item = trieNode->children_.find (subkey);
240 if (item == trieNode->children_.end ())
241 {
242 reachLast = false;
243 break;
244 }
245 else
246 {
247 trieNode = &(*item);
248
249 if (trieNode->payload_ != PayloadTraits::empty_payload)
250 foundNode = trieNode;
251 }
252 }
253
254 return boost::make_tuple (foundNode, reachLast, trieNode);
255 }
256
257 /**
258 * @brief Perform the longest prefix match satisfying preficate
259 * @param key the key for which to perform the longest prefix match
260 *
261 * @return ->second is true if prefix in ->first is longer than key
262 */
263 template<class Predicate>
264 inline boost::tuple<iterator, bool, iterator>
265 find_if (const FullKey &key, Predicate pred)
266 {
267 trie *trieNode = this;
268 iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
269 bool reachLast = true;
270
271 BOOST_FOREACH (const Key &subkey, key)
272 {
273 typename unordered_set::iterator item = trieNode->children_.find (subkey);
274 if (item == trieNode->children_.end ())
275 {
276 reachLast = false;
277 break;
278 }
279 else
280 {
281 trieNode = &(*item);
282
283 if (trieNode->payload_ != PayloadTraits::empty_payload &&
284 pred (trieNode->payload_))
285 {
286 foundNode = trieNode;
287 }
288 }
289 }
290
291 return boost::make_tuple (foundNode, reachLast, trieNode);
292 }
293
294 /**
295 * @brief Find next payload of the sub-trie
296 * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
297 */
298 inline iterator
299 find ()
300 {
301 if (payload_ != PayloadTraits::empty_payload)
302 return this;
303
304 typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
305 for (typename trie::unordered_set::iterator subnode = children_.begin ();
306 subnode != children_.end ();
307 subnode++ )
308 // BOOST_FOREACH (trie &subnode, children_)
309 {
310 iterator value = subnode->find ();
311 if (value != 0)
312 return value;
313 }
314
315 return 0;
316 }
317
318 /**
319 * @brief Find next payload of the sub-trie satisfying the predicate
320 * @param pred predicate
321 * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
322 */
323 template<class Predicate>
324 inline const iterator
325 find_if (Predicate pred)
326 {
327 if (payload_ != PayloadTraits::empty_payload && pred (payload_))
328 return this;
329
330 typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
331 for (typename trie::unordered_set::iterator subnode = children_.begin ();
332 subnode != children_.end ();
333 subnode++ )
334 // BOOST_FOREACH (const trie &subnode, children_)
335 {
336 iterator value = subnode->find_if (pred);
337 if (value != 0)
338 return value;
339 }
340
341 return 0;
342 }
343
344 iterator end ()
345 {
346 return 0;
347 }
348
349 const_iterator end () const
350 {
351 return 0;
352 }
353
354 typename PayloadTraits::const_return_type
355 payload () const
356 {
357 return payload_;
358 }
359
360 typename PayloadTraits::return_type
361 payload ()
362 {
363 return payload_;
364 }
365
366 void
367 set_payload (typename PayloadTraits::insert_type payload)
368 {
369 payload_ = payload;
370 }
371
372 Key key () const
373 {
374 return key_;
375 }
376
377 inline void
378 PrintStat (std::ostream &os) const;
379
380private:
381 //The disposer object function
382 struct trie_delete_disposer
383 {
384 void operator() (trie *delete_this)
385 {
386 delete delete_this;
387 }
388 };
389
390 template<class D>
391 struct array_disposer
392 {
393 void operator() (D *array)
394 {
395 delete [] array;
396 }
397 };
398
399 friend
400 std::ostream&
401 operator<< < > (std::ostream &os, const trie &trie_node);
402
403public:
404 PolicyHook policy_hook_;
405
406private:
407 boost::intrusive::unordered_set_member_hook<> unordered_set_member_hook_;
408
409 // necessary typedefs
410 typedef trie self_type;
411 typedef boost::intrusive::member_hook< trie,
412 boost::intrusive::unordered_set_member_hook< >,
413 &trie::unordered_set_member_hook_ > member_hook;
414
415 typedef boost::intrusive::unordered_set< trie, member_hook > unordered_set;
416 typedef typename unordered_set::bucket_type bucket_type;
417 typedef typename unordered_set::bucket_traits bucket_traits;
418
419 template<class T, class NonConstT>
420 friend class trie_iterator;
421
422 template<class T>
423 friend class trie_point_iterator;
424
425 ////////////////////////////////////////////////
426 // Actual data
427 ////////////////////////////////////////////////
428
429 Key key_; ///< name component
430
431 size_t initialBucketSize_;
432 size_t bucketIncrement_;
433
434 size_t bucketSize_;
435 typedef boost::interprocess::unique_ptr< bucket_type, array_disposer<bucket_type> > buckets_array;
436 buckets_array buckets_;
437 unordered_set children_;
438
439 typename PayloadTraits::storage_type payload_;
440 trie *parent_; // to make cleaning effective
441};
442
443
444
445
446template<typename FullKey, typename PayloadTraits, typename PolicyHook>
447inline std::ostream&
448operator << (std::ostream &os, const trie<FullKey, PayloadTraits, PolicyHook> &trie_node)
449{
450 os << "# " << trie_node.key_ << ((trie_node.payload_ != PayloadTraits::empty_payload)?"*":"") << std::endl;
451 typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
452
453 for (typename trie::unordered_set::const_iterator subnode = trie_node.children_.begin ();
454 subnode != trie_node.children_.end ();
455 subnode++ )
456 // BOOST_FOREACH (const trie &subnode, trie_node.children_)
457 {
458 os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != PayloadTraits::empty_payload)?"*":"") << "\"]\n";
459 os << "\"" << &(*subnode) << "\"" << " [label=\"" << subnode->key_ << ((subnode->payload_ != PayloadTraits::empty_payload)?"*":"") << "\"]""\n";
460
461 os << "\"" << &trie_node << "\"" << " -> " << "\"" << &(*subnode) << "\"" << "\n";
462 os << *subnode;
463 }
464
465 return os;
466}
467
468template<typename FullKey, typename PayloadTraits, typename PolicyHook>
469inline void
470trie<FullKey, PayloadTraits, PolicyHook>
471::PrintStat (std::ostream &os) const
472{
473 os << "# " << key_ << ((payload_ != PayloadTraits::empty_payload)?"*":"") << ": " << children_.size() << " children" << std::endl;
474 for (size_t bucket = 0, maxbucket = children_.bucket_count ();
475 bucket < maxbucket;
476 bucket++)
477 {
478 os << " " << children_.bucket_size (bucket);
479 }
480 os << "\n";
481
482 typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
483 for (typename trie::unordered_set::const_iterator subnode = children_.begin ();
484 subnode != children_.end ();
485 subnode++ )
486 // BOOST_FOREACH (const trie &subnode, children_)
487 {
488 subnode->PrintStat (os);
489 }
490}
491
492
493template<typename FullKey, typename PayloadTraits, typename PolicyHook>
494inline bool
495operator == (const trie<FullKey, PayloadTraits, PolicyHook> &a,
496 const trie<FullKey, PayloadTraits, PolicyHook> &b)
497{
498 return a.key_ == b.key_;
499}
500
501template<typename FullKey, typename PayloadTraits, typename PolicyHook>
502inline std::size_t
503hash_value (const trie<FullKey, PayloadTraits, PolicyHook> &trie_node)
504{
505 return boost::hash_value (trie_node.key_);
506}
507
508
509
510template<class Trie, class NonConstTrie> // hack for boost < 1.47
511class trie_iterator
512{
513public:
514 trie_iterator () : trie_ (0) {}
515 trie_iterator (typename Trie::iterator item) : trie_ (item) {}
516 trie_iterator (Trie &item) : trie_ (&item) {}
517
518 Trie & operator* () { return *trie_; }
519 const Trie & operator* () const { return *trie_; }
520 Trie * operator-> () { return trie_; }
521 const Trie * operator-> () const { return trie_; }
522 bool operator== (trie_iterator<const Trie, NonConstTrie> &other) const { return (trie_ == other.trie_); }
523 bool operator== (trie_iterator<Trie, NonConstTrie> &other) { return (trie_ == other.trie_); }
524 bool operator!= (trie_iterator<const Trie, NonConstTrie> &other) const { return !(*this == other); }
525 bool operator!= (trie_iterator<Trie, NonConstTrie> &other) { return !(*this == other); }
526
527 trie_iterator<Trie,NonConstTrie> &
528 operator++ (int)
529 {
530 if (trie_->children_.size () > 0)
531 trie_ = &(*trie_->children_.begin ());
532 else
533 trie_ = goUp ();
534 return *this;
535 }
536
537 trie_iterator<Trie,NonConstTrie> &
538 operator++ ()
539 {
540 (*this)++;
541 return *this;
542 }
543
544private:
545 typedef typename boost::mpl::if_< boost::is_same<Trie, NonConstTrie>,
546 typename Trie::unordered_set::iterator,
547 typename Trie::unordered_set::const_iterator>::type set_iterator;
548
549 Trie* goUp ()
550 {
551 if (trie_->parent_ != 0)
552 {
553 // typename Trie::unordered_set::iterator item =
554 set_iterator item = const_cast<NonConstTrie*>(trie_)->parent_->children_.iterator_to (const_cast<NonConstTrie&> (*trie_));
555 item++;
556 if (item != trie_->parent_->children_.end ())
557 {
558 return &(*item);
559 }
560 else
561 {
562 trie_ = trie_->parent_;
563 return goUp ();
564 }
565 }
566 else
567 return 0;
568 }
569private:
570 Trie *trie_;
571};
572
573
574template<class Trie>
575class trie_point_iterator
576{
577private:
578 typedef typename boost::mpl::if_< boost::is_same<Trie, const Trie>,
579 typename Trie::unordered_set::const_iterator,
580 typename Trie::unordered_set::iterator>::type set_iterator;
581
582public:
583 trie_point_iterator () : trie_ (0) {}
584 trie_point_iterator (typename Trie::iterator item) : trie_ (item) {}
585 trie_point_iterator (Trie &item)
586 {
587 if (item.children_.size () != 0)
588 trie_ = &*item.children_.begin ();
589 else
590 trie_ = 0;
591 }
592
593 Trie & operator* () { return *trie_; }
594 const Trie & operator* () const { return *trie_; }
595 Trie * operator-> () { return trie_; }
596 const Trie * operator-> () const { return trie_; }
597 bool operator== (trie_point_iterator<const Trie> &other) const { return (trie_ == other.trie_); }
598 bool operator== (trie_point_iterator<Trie> &other) { return (trie_ == other.trie_); }
599 bool operator!= (trie_point_iterator<const Trie> &other) const { return !(*this == other); }
600 bool operator!= (trie_point_iterator<Trie> &other) { return !(*this == other); }
601
602 trie_point_iterator<Trie> &
603 operator++ (int)
604 {
605 if (trie_->parent_ != 0)
606 {
607 set_iterator item = trie_->parent_->children_.iterator_to (*trie_);
608 item ++;
609 if (item == trie_->parent_->children_.end ())
610 trie_ = 0;
611 else
612 trie_ = &*item;
613 }
614 else
615 {
616 trie_ = 0;
617 }
618 return *this;
619 }
620
621 trie_point_iterator<Trie> &
622 operator++ ()
623 {
624 (*this)++;
625 return *this;
626 }
627
628private:
629 Trie *trie_;
630};
631
632
633} // trie
634} // ndn
635
636#endif // NDN_TRIE_TRIE_H_