blob: 5d440d28114017efc8fd0b72e1de7291648c9357 [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
Alexander Afanasyev9a989702012-06-29 17:44:00 -070021#ifndef TRIE_H_
22#define TRIE_H_
23
24#include "ns3/ptr.h"
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070025
26#include <boost/intrusive/unordered_set.hpp>
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070027#include <boost/intrusive/list.hpp>
Alexander Afanasyev9a989702012-06-29 17:44:00 -070028#include <boost/intrusive/set.hpp>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070029#include <boost/functional/hash.hpp>
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070030#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
31#include <boost/tuple/tuple.hpp>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070032
33namespace bi = boost::intrusive;
34
35/////////////////////////////////////////////////////
36// Allow customization for payload
37//
38template<typename Payload>
39struct pointer_payload_traits
40{
41 typedef Payload* pointer_type;
42 typedef const Payload* const_pointer_type;
43
44 static const Payload* empty_payload;
45};
46
47template<typename Payload>
48const Payload*
49pointer_payload_traits<Payload>::empty_payload = 0;
50
51template<typename Payload>
52struct smart_pointer_payload_traits
53{
54 typedef ns3::Ptr<Payload> pointer_type;
55 typedef ns3::Ptr<const Payload> const_pointer_type;
56
57 static const ns3::Ptr<const Payload> empty_payload;
58};
59
60template<typename Payload>
61const ns3::Ptr<const Payload>
62smart_pointer_payload_traits<Payload>::empty_payload = 0;
63
64
65////////////////////////////////////////////////////
66// forward declarations
67//
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070068template<typename FullKey,
69 typename Payload,
Alexander Afanasyev9a989702012-06-29 17:44:00 -070070 typename PayloadTraits,
71 typename PolicyHook >
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070072class trie;
73
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070074template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070075inline std::ostream&
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070076operator << (std::ostream &os,
77 const trie<FullKey, Payload, PayloadTraits, PolicyHook> &trie_node);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070078
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070079template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070080bool
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070081operator== (const trie<FullKey, Payload, PayloadTraits, PolicyHook> &a,
82 const trie<FullKey, Payload, PayloadTraits, PolicyHook> &b);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070083
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070084template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook >
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070085std::size_t
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070086hash_value (const trie<FullKey, Payload, PayloadTraits, PolicyHook> &trie_node);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070087
88///////////////////////////////////////////////////
89// actual definition
90//
91
92
93template<typename FullKey,
Alexander Afanasyev89fb5352012-06-12 22:43:16 -070094 typename Payload, typename PayloadTraits,
95 typename PolicyHook >
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -070096class trie
97{
98public:
99 typedef typename FullKey::partial_type Key;
100
101 typedef trie* iterator;
102 typedef const trie* const_iterator;
103
104 inline
105 trie (const Key &key, size_t bucketSize = 10, size_t bucketIncrement = 10);
106
107 inline
108 ~trie ();
109
110 // actual entry
111 friend bool
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700112 operator== <> (const trie<FullKey, Payload, PayloadTraits, PolicyHook> &a,
113 const trie<FullKey, Payload, PayloadTraits, PolicyHook> &b);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700114
115 friend std::size_t
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700116 hash_value <> (const trie<FullKey, Payload, PayloadTraits, PolicyHook> &trie_node);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700117
118 inline std::pair<iterator, bool>
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700119 insert (const FullKey &key,
120 typename PayloadTraits::const_pointer_type payload);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700121
122 /**
123 * @brief Removes payload (if it exists) and if there are no children, prunes parents trie
124 */
125 inline void
126 erase ();
127
128 /**
129 * @brief Do exactly as erase, but without erasing the payload
130 */
131 inline void
132 prune ();
133
134 /**
135 * @brief Perform the longest prefix match
136 * @param key the key for which to perform the longest prefix match
137 *
138 * @return ->second is true if prefix in ->first is longer than key
139 */
140 inline boost::tuple<iterator, bool, iterator>
141 find (const FullKey &key);
142
143 /**
144 * @brief Find next payload of the sub-trie
145 * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
146 */
147 inline iterator
148 find ();
149
150 /**
151 * @brief Find next payload of the sub-trie satisfying the predicate
152 * @param pred predicate
153 * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
154 */
155 template<class Predicate>
156 inline iterator
157 find_if (Predicate pred);
158
159 iterator end ()
160 {
161 return 0;
162 }
163
164 const_iterator end () const
165 {
166 return 0;
167 }
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700168
169 typename PayloadTraits::const_pointer_type
170 payload () const
171 {
172 return payload_;
173 }
174
175 void
176 set_payload (typename PayloadTraits::const_pointer_type payload)
177 {
178 payload_ = payload;
179 }
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700180
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700181 inline void
182 PrintStat (std::ostream &os) const;
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700183
184private:
185 //The disposer object function
186 struct trie_delete_disposer
187 {
188 void operator() (trie *delete_this)
189 {
190 // std::cout << "Deleting " << delete_this << "\n";
191 delete delete_this;
192 }
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700193 };
194
195 template<class D>
196 struct array_disposer
197 {
198 void operator() (D *array)
199 {
200 delete [] array;
201 }
202 };
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700203
204 friend
205 std::ostream&
206 operator<< < > (std::ostream &os, const trie &trie_node);
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700207
208public:
209 PolicyHook policy_hook_;
210
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700211private:
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700212 bi::unordered_set_member_hook<> unordered_set_member_hook_;
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700213
214 // necessary typedefs
215 typedef trie self_type;
216 typedef bi::member_hook< trie,
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700217 bi::unordered_set_member_hook< >, &trie::unordered_set_member_hook_ > member_hook;
218 typedef bi::unordered_set< trie, member_hook > unordered_set;
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700219 typedef typename unordered_set::bucket_type bucket_type;
220 typedef typename unordered_set::bucket_traits bucket_traits;
221
222 ////////////////////////////////////////////////
223 // Actual data
224 ////////////////////////////////////////////////
225
226 Key key_; ///< name component
227
228 size_t initialBucketSize_;
229 size_t bucketIncrement_;
230
231 size_t bucketSize_;
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700232 typedef boost::interprocess::unique_ptr< bucket_type, array_disposer<bucket_type> > buckets_array;
233 buckets_array buckets_;
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700234 unordered_set children_;
235
236 typename PayloadTraits::const_pointer_type payload_;
237 trie *parent_; // to make cleaning effective
238};
239
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700240template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
241trie<FullKey, Payload, PayloadTraits, PolicyHook>
242::trie (const trie::Key &key, size_t bucketSize, size_t bucketIncrement)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700243 : key_ (key)
244 , initialBucketSize_ (bucketSize)
245 , bucketIncrement_ (bucketIncrement)
246 , bucketSize_ (initialBucketSize_)
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700247 , buckets_ (new bucket_type [bucketSize_]) //cannot use normal pointer, because lifetime of buckets should be larger than lifetime of the container
248 , children_ (bucket_traits (buckets_.get (), bucketSize_))
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700249 , payload_ (PayloadTraits::empty_payload)
250 , parent_ (0)
251{
252}
253
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700254template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
255trie<FullKey, Payload, PayloadTraits, PolicyHook>
256::~trie ()
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700257{
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700258 payload_ = PayloadTraits::empty_payload; // necessary for smart pointers...
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700259 children_.clear_and_dispose (trie_delete_disposer ());
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700260}
261
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700262template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700263inline
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700264std::pair<typename trie<FullKey, Payload, PayloadTraits, PolicyHook>::iterator, bool>
265trie<FullKey, Payload, PayloadTraits, PolicyHook>
266::insert (const FullKey &key, typename PayloadTraits::const_pointer_type payload)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700267{
268 trie *trieNode = this;
269
270 BOOST_FOREACH (const Key &subkey, key)
271 {
272 typename unordered_set::iterator item = trieNode->children_.find (subkey);
273 if (item == trieNode->children_.end ())
274 {
275 trie *newNode = new trie (subkey, initialBucketSize_, bucketIncrement_);
276 // std::cout << "new " << newNode << "\n";
277 newNode->parent_ = trieNode;
278
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700279 if (trieNode->children_.size () >= trieNode->bucketSize_)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700280 {
281 trieNode->bucketSize_ += trieNode->bucketIncrement_;
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700282 buckets_array newBuckets (new bucket_type [trieNode->bucketSize_]);
283 trieNode->children_.rehash (bucket_traits (newBuckets.get (), trieNode->bucketSize_));
284 trieNode->buckets_.swap (newBuckets);
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700285 }
286
287 std::pair< typename unordered_set::iterator, bool > ret =
288 trieNode->children_.insert (*newNode);
289
290 trieNode = &(*ret.first);
291 }
292 else
293 trieNode = &(*item);
294 }
295
296 if (trieNode->payload_ == 0)
297 {
298 trieNode->payload_ = payload;
299 return std::make_pair (trieNode, true);
300 }
301 else
302 return std::make_pair (trieNode, false);
303}
304
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700305template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700306inline
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700307boost::tuple<typename trie<FullKey, Payload, PayloadTraits, PolicyHook>::iterator,
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700308 bool,
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700309 typename trie<FullKey, Payload, PayloadTraits, PolicyHook>::iterator>
310trie<FullKey, Payload, PayloadTraits, PolicyHook>
311::find (const FullKey &key)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700312{
313 trie *trieNode = this;
314 iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
315 bool reachLast = true;
316
317 BOOST_FOREACH (const Key &subkey, key)
318 {
319 typename unordered_set::iterator item = trieNode->children_.find (subkey);
320 if (item == trieNode->children_.end ())
321 {
322 reachLast = false;
323 break;
324 }
325 else
326 {
327 trieNode = &(*item);
328
329 if (trieNode->payload_ != PayloadTraits::empty_payload)
330 foundNode = trieNode;
331 }
332 }
333
334 return boost::make_tuple (foundNode, reachLast, trieNode);
335}
336
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700337template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
338inline typename trie<FullKey, Payload, PayloadTraits, PolicyHook>::iterator
339trie<FullKey, Payload, PayloadTraits, PolicyHook>
340::find ()
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700341{
342 if (payload_ != PayloadTraits::empty_payload)
343 return this;
344
Alexander Afanasyev9a989702012-06-29 17:44:00 -0700345 typedef trie<FullKey, Payload, PayloadTraits, PolicyHook> trie;
Alexander Afanasyevb0c43892012-06-13 00:52:58 -0700346 BOOST_FOREACH (trie &subnode, children_)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700347 {
348 iterator value = subnode.find ();
349 if (value != 0)
350 return value;
351 }
352
353 return 0;
354}
355
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700356template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700357template<class Predicate>
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700358inline typename trie<FullKey, Payload, PayloadTraits, PolicyHook>::iterator
359trie<FullKey, Payload, PayloadTraits, PolicyHook>
360::find_if (Predicate pred)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700361{
362 if (payload_ != PayloadTraits::empty_payload && pred (payload_))
363 return this;
364
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700365 typedef trie<FullKey, Payload, PayloadTraits, PolicyHook> trie;
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700366 BOOST_FOREACH (const trie &subnode, children_)
367 {
368 iterator value = subnode.find ();
369 if (value != 0)
370 return value;
371 }
372
373 return 0;
374}
375
376
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700377template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700378inline void
Alexander Afanasyevb0c43892012-06-13 00:52:58 -0700379trie<FullKey, Payload, PayloadTraits, PolicyHook>
380::erase ()
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700381{
382 payload_ = PayloadTraits::empty_payload;
383 prune ();
384}
385
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700386template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700387inline void
Alexander Afanasyevb0c43892012-06-13 00:52:58 -0700388trie<FullKey, Payload, PayloadTraits, PolicyHook>
389::prune ()
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700390{
391 if (payload_ == 0 && children_.size () == 0)
392 {
393 if (parent_ == 0) return;
394
395 trie *parent = parent_;
396 parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
397
398 parent->prune ();
399 }
400}
401
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700402template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700403inline std::ostream&
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700404operator << (std::ostream &os, const trie<FullKey, Payload, PayloadTraits, PolicyHook> &trie_node)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700405{
406 os << "# " << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << std::endl;
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700407 typedef trie<FullKey, Payload, PayloadTraits, PolicyHook> trie;
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700408 BOOST_FOREACH (const trie &subnode, trie_node.children_)
409 {
410 os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << "\"]\n";
411 os << "\"" << &subnode << "\"" << " [label=\"" << subnode.key_ << ((subnode.payload_ != 0)?"*":"") << "\"]""\n";
412
413 os << "\"" << &trie_node << "\"" << " -> " << "\"" << &subnode << "\"" << "\n";
414 os << subnode;
415 }
416
417 return os;
418}
419
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700420template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
421inline void
Alexander Afanasyevb0c43892012-06-13 00:52:58 -0700422trie<FullKey, Payload, PayloadTraits, PolicyHook>
423::PrintStat (std::ostream &os) const
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700424{
425 os << "# " << key_ << ((payload_ != 0)?"*":"") << ": " << children_.size() << " children" << std::endl;
426 for (size_t bucket = 0, maxbucket = children_.bucket_count ();
427 bucket < maxbucket;
428 bucket++)
429 {
430 os << " " << children_.bucket_size (bucket);
431 }
432 os << "\n";
433
434 typedef trie<FullKey, Payload, PayloadTraits, PolicyHook> trie;
435 BOOST_FOREACH (const trie &subnode, children_)
436 {
437 subnode.PrintStat (os);
438 }
439}
440
441
442template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700443inline bool
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700444operator == (const trie<FullKey, Payload, PayloadTraits, PolicyHook> &a,
445 const trie<FullKey, Payload, PayloadTraits, PolicyHook> &b)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700446{
447 return a.key_ == b.key_;
448}
449
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700450template<typename FullKey, typename Payload, typename PayloadTraits, typename PolicyHook>
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700451inline std::size_t
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700452hash_value (const trie<FullKey, Payload, PayloadTraits, PolicyHook> &trie_node)
Alexander Afanasyevfd0c41c2012-06-11 22:15:49 -0700453{
454 return boost::hash_value (trie_node.key_);
455}
Alexander Afanasyev89fb5352012-06-12 22:43:16 -0700456
Alexander Afanasyev9a989702012-06-29 17:44:00 -0700457#endif // TRIE_H_