blob: 5a0d896889f3c66632485f61c12406888bfd23ca [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 TRIE_TRIE_WITH_POLICY_H_
12#define TRIE_TRIE_WITH_POLICY_H_
13
14#include "trie.h"
15
16namespace ndn {
17namespace trie {
18
19template<typename FullKey,
20 typename PayloadTraits,
21 typename PolicyTraits
22 >
23class trie_with_policy
24{
25public:
26 typedef trie< FullKey,
27 PayloadTraits,
28 typename PolicyTraits::policy_hook_type > parent_trie;
29
30 typedef typename parent_trie::iterator iterator;
31 typedef typename parent_trie::const_iterator const_iterator;
32 typedef typename parent_trie::payload_traits payload_traits;
33
34 typedef typename PolicyTraits::template policy<
35 trie_with_policy<FullKey, PayloadTraits, PolicyTraits>,
36 parent_trie,
37 typename PolicyTraits::template container_hook<parent_trie>::type >::type policy_container;
38
39 inline
40 trie_with_policy (size_t bucketSize = 10, size_t bucketIncrement = 10)
41 : trie_ ("", bucketSize, bucketIncrement)
42 , policy_ (*this)
43 {
44 }
45
46 inline std::pair< iterator, bool >
47 insert (const FullKey &key, typename PayloadTraits::insert_type payload)
48 {
49 std::pair<iterator, bool> item =
50 trie_.insert (key, payload);
51
52 if (item.second) // real insert
53 {
54 bool ok = policy_.insert (s_iterator_to (item.first));
55 if (!ok)
56 {
57 item.first->erase (); // cannot insert
58 return std::make_pair (end (), false);
59 }
60 }
61 else
62 {
63 return std::make_pair (s_iterator_to (item.first), false);
64 }
65
66 return item;
67 }
68
69 inline void
70 erase (const FullKey &key)
71 {
72 iterator foundItem, lastItem;
73 bool reachLast;
74 boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
75
76 if (!reachLast || lastItem->payload () == PayloadTraits::empty_payload)
77 return; // nothing to invalidate
78
79 erase (lastItem);
80 }
81
82 inline void
83 erase (iterator node)
84 {
85 if (node == end ()) return;
86
87 policy_.erase (s_iterator_to (node));
88 node->erase (); // will do cleanup here
89 }
90
91 inline void
92 clear ()
93 {
94 policy_.clear ();
95 trie_.clear ();
96 }
97
98 template<typename Modifier>
99 bool
100 modify (iterator position, Modifier mod)
101 {
102 if (position == end ()) return false;
103 if (position->payload () == PayloadTraits::empty_payload) return false;
104
105 mod (*position->payload ());
106 policy_.update (position);
107 return true;
108 }
109
110 /**
111 * @brief Find a node that has the exact match with the key
112 */
113 inline iterator
114 find_exact (const FullKey &key)
115 {
116 iterator foundItem, lastItem;
117 bool reachLast;
118 boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
119
120 if (!reachLast || lastItem->payload () == PayloadTraits::empty_payload)
121 return end ();
122
123 return lastItem;
124 }
125
126 /**
127 * @brief Find a node that has the longest common prefix with key (FIB/PIT lookup)
128 */
129 inline iterator
130 longest_prefix_match (const FullKey &key)
131 {
132 iterator foundItem, lastItem;
133 bool reachLast;
134 boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
135 if (foundItem != trie_.end ())
136 {
137 policy_.lookup (s_iterator_to (foundItem));
138 }
139 return foundItem;
140 }
141
142 /**
143 * @brief Find a node that has the longest common prefix with key (FIB/PIT lookup)
144 */
145 template<class Predicate>
146 inline iterator
147 longest_prefix_match_if (const FullKey &key, Predicate pred)
148 {
149 iterator foundItem, lastItem;
150 bool reachLast;
151 boost::tie (foundItem, reachLast, lastItem) = trie_.find_if (key, pred);
152 if (foundItem != trie_.end ())
153 {
154 policy_.lookup (s_iterator_to (foundItem));
155 }
156 return foundItem;
157 }
158
159 // /**
160 // * @brief Const version of the longest common prefix match
161 // * (semi-const, because there could be update of the policy anyways)
162 // */
163 // inline const_iterator
164 // longest_prefix_match (const FullKey &key) const
165 // {
166 // return static_cast<trie_with_policy*> (this)->longest_prefix_match (key);
167 // }
168
169 /**
170 * @brief Find a node that has prefix at least as the key (cache lookup)
171 */
172 inline iterator
173 deepest_prefix_match (const FullKey &key)
174 {
175 iterator foundItem, lastItem;
176 bool reachLast;
177 boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
178
179 // guard in case we don't have anything in the trie
180 if (lastItem == trie_.end ())
181 return trie_.end ();
182
183 if (reachLast)
184 {
185 if (foundItem == trie_.end ())
186 {
187 foundItem = lastItem->find (); // should be something
188 }
189 policy_.lookup (s_iterator_to (foundItem));
190 return foundItem;
191 }
192 else
193 { // couldn't find a node that has prefix at least as key
194 return trie_.end ();
195 }
196 }
197
198 /**
199 * @brief Find a node that has prefix at least as the key
200 */
201 template<class Predicate>
202 inline iterator
203 deepest_prefix_match (const FullKey &key, Predicate pred)
204 {
205 iterator foundItem, lastItem;
206 bool reachLast;
207 boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
208
209 // guard in case we don't have anything in the trie
210 if (lastItem == trie_.end ())
211 return trie_.end ();
212
213 if (reachLast)
214 {
215 foundItem = lastItem->find_if (pred); // may or may not find something
216 if (foundItem == trie_.end ())
217 {
218 return trie_.end ();
219 }
220 policy_.lookup (s_iterator_to (foundItem));
221 return foundItem;
222 }
223 else
224 { // couldn't find a node that has prefix at least as key
225 return trie_.end ();
226 }
227 }
228
229 iterator end () const
230 {
231 return 0;
232 }
233
234 const parent_trie &
235 getTrie () const { return trie_; }
236
237 parent_trie &
238 getTrie () { return trie_; }
239
240 const policy_container &
241 getPolicy () const { return policy_; }
242
243 policy_container &
244 getPolicy () { return policy_; }
245
246 static inline iterator
247 s_iterator_to (typename parent_trie::iterator item)
248 {
249 if (item == 0)
250 return 0;
251 else
252 return &(*item);
253 }
254
255private:
256 parent_trie trie_;
257 mutable policy_container policy_;
258};
259
260} // trie
261} // ndn
262
263#endif // TRIE_TRIE_WITH_POLICY_H_