1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
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 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL. If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so. If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact: Jari Sundell <jaris@ifi.uio.no>
33 //
34 // Skomakerveien 33
35 // 3185 Skoppum, NORWAY
36
37 #ifndef LIBTORRENT_QUEUE_BUCKETS_H
38 #define LIBTORRENT_QUEUE_BUCKETS_H
39
40 #include <algorithm>
41 #include <deque>
42 #include lt_tr1_functional
43 #include lt_tr1_array
44
45 namespace torrent {
46
47 template <typename Type, typename Constants>
48 class queue_buckets : private std::array<std::deque<Type>, Constants::bucket_count> {
49 public:
50 typedef std::deque<Type> queue_type;
51 typedef std::array<queue_type, Constants::bucket_count> base_type;
52
53 typedef Constants constants;
54
55 typedef typename queue_type::value_type value_type;
56 typedef typename queue_type::size_type size_type;
57 typedef typename queue_type::difference_type difference_type;
58
59 typedef typename queue_type::iterator iterator;
60 typedef typename queue_type::const_iterator const_iterator;
61
queue_size(int idx)62 size_type queue_size(int idx) const { return queue_at(idx).size(); }
queue_empty(int idx)63 bool queue_empty(int idx) const { return queue_at(idx).empty(); }
64
65 bool empty() const;
66
begin(int idx)67 iterator begin(int idx) { return queue_at(idx).begin(); }
end(int idx)68 iterator end(int idx) { return queue_at(idx).end(); }
begin(int idx)69 const_iterator begin(int idx) const { return queue_at(idx).begin(); }
end(int idx)70 const_iterator end(int idx) const { return queue_at(idx).end(); }
71
front(int idx)72 value_type front(int idx) { return queue_at(idx).front(); }
back(int idx)73 value_type back(int idx) { return queue_at(idx).back(); }
front(int idx)74 const value_type front(int idx) const { return queue_at(idx).front(); }
back(int idx)75 const value_type back(int idx) const { return queue_at(idx).back(); }
76
77 void pop_front(int idx);
78 void pop_back(int idx);
79
80 value_type pop_and_front(int idx);
81 value_type pop_and_back(int idx);
82
83 void push_front(int idx, const value_type& value_type);
84 void push_back(int idx, const value_type& value_type);
85
86 value_type take(int idx, iterator itr);
87
88 void clear(int idx);
89 void destroy(int idx, iterator begin, iterator end);
90
91 void move_to(int src_idx, iterator src_begin, iterator src_end, int dst_idx);
92 void move_all_to(int src_idx, int dst_idx);
93
94 private:
queue_at(int idx)95 queue_type& queue_at(int idx) { return base_type::operator[](idx); }
queue_at(int idx)96 const queue_type& queue_at(int idx) const { return base_type::operator[](idx); }
97 };
98
99 //
100 // Helper methods:
101 //
102
103 template<typename QueueBucket, typename Ftor>
104 void
queue_bucket_for_all_in_queue(QueueBucket & queues,int idx,Ftor ftor)105 queue_bucket_for_all_in_queue(QueueBucket& queues, int idx, Ftor ftor) {
106 std::for_each(queues.begin(idx), queues.end(idx), ftor);
107 }
108
109 template<typename QueueBucket, typename Ftor>
110 void
queue_bucket_for_all_in_queue(const QueueBucket & queues,int idx,Ftor ftor)111 queue_bucket_for_all_in_queue(const QueueBucket& queues, int idx, Ftor ftor) {
112 std::for_each(queues.begin(idx), queues.end(idx), ftor);
113 }
114
115 template<typename QueueBucket, typename Ftor>
116 inline typename QueueBucket::iterator
queue_bucket_find_if_in_queue(QueueBucket & queues,int idx,Ftor ftor)117 queue_bucket_find_if_in_queue(QueueBucket& queues, int idx, Ftor ftor) {
118 return std::find_if(queues.begin(idx), queues.end(idx), ftor);
119 }
120
121 template<typename QueueBucket, typename Ftor>
122 inline typename QueueBucket::const_iterator
queue_bucket_find_if_in_queue(const QueueBucket & queues,int idx,Ftor ftor)123 queue_bucket_find_if_in_queue(const QueueBucket& queues, int idx, Ftor ftor) {
124 return std::find_if(queues.begin(idx), queues.end(idx), ftor);
125 }
126
127 template<typename QueueBucket, typename Ftor>
128 inline std::pair<int, typename QueueBucket::iterator>
queue_bucket_find_if_in_any(QueueBucket & queues,Ftor ftor)129 queue_bucket_find_if_in_any(QueueBucket& queues, Ftor ftor) {
130 for (int i = 0; i < QueueBucket::constants::bucket_count; i++) {
131 typename QueueBucket::iterator itr = std::find_if(queues.begin(i), queues.end(i), ftor);
132
133 if (itr != queues.end(i))
134 return std::make_pair(i, itr);
135 }
136
137 return std::make_pair(QueueBucket::constants::bucket_count,
138 queues.end(QueueBucket::constants::bucket_count - 1));
139 }
140
141 template<typename QueueBucket, typename Ftor>
142 inline std::pair<int, typename QueueBucket::const_iterator>
queue_bucket_find_if_in_any(const QueueBucket & queues,Ftor ftor)143 queue_bucket_find_if_in_any(const QueueBucket& queues, Ftor ftor) {
144 for (int i = 0; i < QueueBucket::constants::bucket_count; i++) {
145 typename QueueBucket::const_iterator itr = std::find_if(queues.begin(i), queues.end(i), ftor);
146
147 if (itr != queues.end(i))
148 return std::make_pair(i, itr);
149 }
150
151 return std::make_pair(QueueBucket::constants::bucket_count,
152 queues.end(QueueBucket::constants::bucket_count - 1));
153 }
154
155 //
156 // Implementation:
157 //
158
159 // TODO: Consider renaming bucket to queue.
160
161 // TODO: when adding removal/etc of element or ranges do logging on if
162 // it hit the first element or had to search.
163
164 template <typename Type, typename Constants>
165 inline bool
empty()166 queue_buckets<Type, Constants>::empty() const {
167 for (int i = 0; i < constants::bucket_count; i++)
168 if (!queue_empty(i))
169 return false;
170
171 return true;
172 }
173
174 template <typename Type, typename Constants>
175 inline void
pop_front(int idx)176 queue_buckets<Type, Constants>::pop_front(int idx) {
177 queue_at(idx).pop_front();
178
179 instrumentation_update(constants::instrumentation_removed[idx], 1);
180 instrumentation_update(constants::instrumentation_total[idx], -1);
181 }
182
183 template <typename Type, typename Constants>
184 inline void
pop_back(int idx)185 queue_buckets<Type, Constants>::pop_back(int idx) {
186 queue_at(idx).pop_back();
187
188 instrumentation_update(constants::instrumentation_removed[idx], 1);
189 instrumentation_update(constants::instrumentation_total[idx], -1);
190 }
191
192 template <typename Type, typename Constants>
193 inline typename queue_buckets<Type, Constants>::value_type
pop_and_front(int idx)194 queue_buckets<Type, Constants>::pop_and_front(int idx) {
195 value_type v = queue_at(idx).front();
196 pop_front(idx);
197 return v;
198 }
199
200 template <typename Type, typename Constants>
201 inline typename queue_buckets<Type, Constants>::value_type
pop_and_back(int idx)202 queue_buckets<Type, Constants>::pop_and_back(int idx) {
203 value_type v = queue_at(idx).back();
204 pop_back(idx);
205 return v;
206 }
207
208 template <typename Type, typename Constants>
209 inline void
push_front(int idx,const value_type & value)210 queue_buckets<Type, Constants>::push_front(int idx, const value_type& value) {
211 queue_at(idx).push_front(value);
212
213 instrumentation_update(constants::instrumentation_added[idx], 1);
214 instrumentation_update(constants::instrumentation_total[idx], 1);
215 }
216
217 template <typename Type, typename Constants>
218 inline void
push_back(int idx,const value_type & value)219 queue_buckets<Type, Constants>::push_back(int idx, const value_type& value) {
220 queue_at(idx).push_back(value);
221
222 instrumentation_update(constants::instrumentation_added[idx], 1);
223 instrumentation_update(constants::instrumentation_total[idx], 1);
224 }
225
226 template <typename Type, typename Constants>
227 inline typename queue_buckets<Type, Constants>::value_type
take(int idx,iterator itr)228 queue_buckets<Type, Constants>::take(int idx, iterator itr) {
229 value_type v = *itr;
230 queue_at(idx).erase(itr);
231
232 instrumentation_update(constants::instrumentation_removed[idx], 1);
233 instrumentation_update(constants::instrumentation_total[idx], -1);
234
235 // TODO: Add 'taken' instrumentation.
236
237 return v;
238 }
239
240 template <typename Type, typename Constants>
241 inline void
clear(int idx)242 queue_buckets<Type, Constants>::clear(int idx) {
243 destroy(idx, begin(idx), end(idx));
244 }
245
246 template <typename Type, typename Constants>
247 inline void
destroy(int idx,iterator begin,iterator end)248 queue_buckets<Type, Constants>::destroy(int idx, iterator begin, iterator end) {
249 difference_type difference = std::distance(begin, end);
250 instrumentation_update(constants::instrumentation_removed[idx], difference);
251 instrumentation_update(constants::instrumentation_total[idx], -difference);
252
253 // Consider moving these to a temporary dequeue before releasing:
254 std::for_each(begin, end, std::function<void (value_type&)>(&constants::template destroy<value_type>));
255 queue_at(idx).erase(begin, end);
256 }
257
258 template <typename Type, typename Constants>
259 inline void
move_to(int src_idx,iterator src_begin,iterator src_end,int dst_idx)260 queue_buckets<Type, Constants>::move_to(int src_idx, iterator src_begin, iterator src_end,
261 int dst_idx) {
262 difference_type difference = std::distance(src_begin, src_end);
263 instrumentation_update(constants::instrumentation_moved[src_idx], difference);
264 instrumentation_update(constants::instrumentation_total[src_idx], -difference);
265 instrumentation_update(constants::instrumentation_added[dst_idx], difference);
266 instrumentation_update(constants::instrumentation_total[dst_idx], difference);
267
268 // TODO: Check for better move operations:
269 if (queue_at(dst_idx).empty() &&
270 src_begin == queue_at(src_idx).begin() &&
271 src_end == queue_at(src_idx).end()) {
272 queue_at(dst_idx).swap(queue_at(src_idx));
273 } else {
274 queue_at(dst_idx).insert(queue_at(dst_idx).end(), src_begin, src_end);
275 queue_at(src_idx).erase(src_begin, src_end);
276 }
277 }
278
279 template <typename Type, typename Constants>
280 inline void
move_all_to(int src_idx,int dst_idx)281 queue_buckets<Type, Constants>::move_all_to(int src_idx, int dst_idx) {
282 move_to(src_idx, queue_at(src_idx).begin(), queue_at(src_idx).end(), dst_idx);
283 }
284
285 }
286
287 #endif // LIBTORRENT_QUEUE_BUCKETS_H
288