]> git.proxmox.com Git - ceph.git/blame - ceph/src/include/interval_set.h
bump version to 12.0.3-pve3
[ceph.git] / ceph / src / include / interval_set.h
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15
16#ifndef CEPH_INTERVAL_SET_H
17#define CEPH_INTERVAL_SET_H
18
19#include <iterator>
20#include <map>
21#include <ostream>
22
23#include "encoding.h"
24
25#ifndef MIN
26# define MIN(a,b) ((a)<=(b) ? (a):(b))
27#endif
28#ifndef MAX
29# define MAX(a,b) ((a)>=(b) ? (a):(b))
30#endif
31
32
33template<typename T>
34class interval_set {
35 public:
36
37 class const_iterator;
38
39 class iterator : public std::iterator <std::forward_iterator_tag, T>
40 {
41 public:
42 explicit iterator(typename std::map<T,T>::iterator iter)
43 : _iter(iter)
44 { }
45
46 // For the copy constructor and assignment operator, the compiler-generated functions, which
47 // perform simple bitwise copying, should be fine.
48
49 bool operator==(const iterator& rhs) const {
50 return (_iter == rhs._iter);
51 }
52
53 bool operator!=(const iterator& rhs) const {
54 return (_iter != rhs._iter);
55 }
56
57 // Dereference this iterator to get a pair.
58 std::pair < T, T > &operator*() {
59 return *_iter;
60 }
61
62 // Return the interval start.
63 T get_start() const {
64 return _iter->first;
65 }
66
67 // Return the interval length.
68 T get_len() const {
69 return _iter->second;
70 }
71
72 // Set the interval length.
73 void set_len(T len) {
74 _iter->second = len;
75 }
76
77 // Preincrement
78 iterator &operator++()
79 {
80 ++_iter;
81 return *this;
82 }
83
84 // Postincrement
85 iterator operator++(int)
86 {
87 iterator prev(_iter);
88 ++_iter;
89 return prev;
90 }
91
92 friend class interval_set<T>::const_iterator;
93
94 protected:
95 typename std::map<T,T>::iterator _iter;
96 friend class interval_set<T>;
97 };
98
99 class const_iterator : public std::iterator <std::forward_iterator_tag, T>
100 {
101 public:
102 explicit const_iterator(typename std::map<T,T>::const_iterator iter)
103 : _iter(iter)
104 { }
105
106 const_iterator(const iterator &i)
107 : _iter(i._iter)
108 { }
109
110 // For the copy constructor and assignment operator, the compiler-generated functions, which
111 // perform simple bitwise copying, should be fine.
112
113 bool operator==(const const_iterator& rhs) const {
114 return (_iter == rhs._iter);
115 }
116
117 bool operator!=(const const_iterator& rhs) const {
118 return (_iter != rhs._iter);
119 }
120
121 // Dereference this iterator to get a pair.
122 std::pair < T, T > operator*() const {
123 return *_iter;
124 }
125
126 // Return the interval start.
127 T get_start() const {
128 return _iter->first;
129 }
130
131 // Return the interval length.
132 T get_len() const {
133 return _iter->second;
134 }
135
136 // Preincrement
137 const_iterator &operator++()
138 {
139 ++_iter;
140 return *this;
141 }
142
143 // Postincrement
144 const_iterator operator++(int)
145 {
146 const_iterator prev(_iter);
147 ++_iter;
148 return prev;
149 }
150
151 protected:
152 typename std::map<T,T>::const_iterator _iter;
153 };
154
155 interval_set() : _size(0) {}
156 interval_set(std::map<T,T>& other) {
157 m.swap(other);
158 _size = 0;
159 for (auto& i : m) {
160 _size += i.second;
161 }
162 }
163
164 int num_intervals() const
165 {
166 return m.size();
167 }
168
169 typename interval_set<T>::iterator begin() {
170 return typename interval_set<T>::iterator(m.begin());
171 }
172
173 typename interval_set<T>::iterator lower_bound(T start) {
174 return typename interval_set<T>::iterator(find_inc_m(start));
175 }
176
177 typename interval_set<T>::iterator end() {
178 return typename interval_set<T>::iterator(m.end());
179 }
180
181 typename interval_set<T>::const_iterator begin() const {
182 return typename interval_set<T>::const_iterator(m.begin());
183 }
184
185 typename interval_set<T>::const_iterator lower_bound(T start) const {
186 return typename interval_set<T>::const_iterator(find_inc(start));
187 }
188
189 typename interval_set<T>::const_iterator end() const {
190 return typename interval_set<T>::const_iterator(m.end());
191 }
192
193 // helpers
194 private:
195 typename std::map<T,T>::const_iterator find_inc(T start) const {
196 typename std::map<T,T>::const_iterator p = m.lower_bound(start); // p->first >= start
197 if (p != m.begin() &&
198 (p == m.end() || p->first > start)) {
199 p--; // might overlap?
200 if (p->first + p->second <= start)
201 p++; // it doesn't.
202 }
203 return p;
204 }
205
206 typename std::map<T,T>::iterator find_inc_m(T start) {
207 typename std::map<T,T>::iterator p = m.lower_bound(start);
208 if (p != m.begin() &&
209 (p == m.end() || p->first > start)) {
210 p--; // might overlap?
211 if (p->first + p->second <= start)
212 p++; // it doesn't.
213 }
214 return p;
215 }
216
217 typename std::map<T,T>::const_iterator find_adj(T start) const {
218 typename std::map<T,T>::const_iterator p = m.lower_bound(start);
219 if (p != m.begin() &&
220 (p == m.end() || p->first > start)) {
221 p--; // might touch?
222 if (p->first + p->second < start)
223 p++; // it doesn't.
224 }
225 return p;
226 }
227
228 typename std::map<T,T>::iterator find_adj_m(T start) {
229 typename std::map<T,T>::iterator p = m.lower_bound(start);
230 if (p != m.begin() &&
231 (p == m.end() || p->first > start)) {
232 p--; // might touch?
233 if (p->first + p->second < start)
234 p++; // it doesn't.
235 }
236 return p;
237 }
238
239 public:
240 bool operator==(const interval_set& other) const {
241 return _size == other._size && m == other.m;
242 }
243
244 int64_t size() const {
245 return _size;
246 }
247
248 void bound_encode(size_t& p) const {
249 denc_traits<std::map<T,T>>::bound_encode(m, p);
250 }
251 void encode(bufferlist::contiguous_appender& p) const {
252 denc_traits<std::map<T,T>>::encode(m, p);
253 }
254 void decode(bufferptr::iterator& p) {
255 denc_traits<std::map<T,T>>::decode(m, p);
256 _size = 0;
257 for (typename std::map<T,T>::const_iterator i = m.begin();
258 i != m.end();
259 i++)
260 _size += i->second;
261 }
262
263 void encode_nohead(bufferlist::contiguous_appender& p) const {
264 denc_traits<std::map<T,T>>::encode_nohead(m, p);
265 }
266 void decode_nohead(int n, bufferptr::iterator& p) {
267 denc_traits<std::map<T,T>>::decode_nohead(n, m, p);
268 _size = 0;
269 for (typename std::map<T,T>::const_iterator i = m.begin();
270 i != m.end();
271 i++)
272 _size += i->second;
273 }
274
275 void clear() {
276 m.clear();
277 _size = 0;
278 }
279
280 bool contains(T i, T *pstart=0, T *plen=0) const {
281 typename std::map<T,T>::const_iterator p = find_inc(i);
282 if (p == m.end()) return false;
283 if (p->first > i) return false;
284 if (p->first+p->second <= i) return false;
285 assert(p->first <= i && p->first+p->second > i);
286 if (pstart)
287 *pstart = p->first;
288 if (plen)
289 *plen = p->second;
290 return true;
291 }
292 bool contains(T start, T len) const {
293 typename std::map<T,T>::const_iterator p = find_inc(start);
294 if (p == m.end()) return false;
295 if (p->first > start) return false;
296 if (p->first+p->second <= start) return false;
297 assert(p->first <= start && p->first+p->second > start);
298 if (p->first+p->second < start+len) return false;
299 return true;
300 }
301 bool intersects(T start, T len) const {
302 interval_set a;
303 a.insert(start, len);
304 interval_set i;
305 i.intersection_of( *this, a );
306 if (i.empty()) return false;
307 return true;
308 }
309
310 // outer range of set
311 bool empty() const {
312 return m.empty();
313 }
314 T range_start() const {
315 assert(!empty());
316 typename std::map<T,T>::const_iterator p = m.begin();
317 return p->first;
318 }
319 T range_end() const {
320 assert(!empty());
321 typename std::map<T,T>::const_iterator p = m.end();
322 p--;
323 return p->first+p->second;
324 }
325
326 // interval start after p (where p not in set)
327 bool starts_after(T i) const {
328 assert(!contains(i));
329 typename std::map<T,T>::const_iterator p = find_inc(i);
330 if (p == m.end()) return false;
331 return true;
332 }
333 T start_after(T i) const {
334 assert(!contains(i));
335 typename std::map<T,T>::const_iterator p = find_inc(i);
336 return p->first;
337 }
338
339 // interval end that contains start
340 T end_after(T start) const {
341 assert(contains(start));
342 typename std::map<T,T>::const_iterator p = find_inc(start);
343 return p->first+p->second;
344 }
345
346 void insert(T val) {
347 insert(val, 1);
348 }
349
350 void insert(T start, T len, T *pstart=0, T *plen=0) {
351 //cout << "insert " << start << "~" << len << endl;
352 assert(len > 0);
353 _size += len;
354 typename std::map<T,T>::iterator p = find_adj_m(start);
355 if (p == m.end()) {
356 m[start] = len; // new interval
357 if (pstart)
358 *pstart = start;
359 if (plen)
360 *plen = len;
361 } else {
362 if (p->first < start) {
363
364 if (p->first + p->second != start) {
365 //cout << "p is " << p->first << "~" << p->second << ", start is " << start << ", len is " << len << endl;
366 ceph_abort();
367 }
368
369 p->second += len; // append to end
370
371 typename std::map<T,T>::iterator n = p;
372 n++;
373 if (n != m.end() &&
374 start+len == n->first) { // combine with next, too!
375 p->second += n->second;
376 m.erase(n);
377 }
378 if (pstart)
379 *pstart = p->first;
380 if (plen)
381 *plen = p->second;
382 } else {
383 if (start+len == p->first) {
384 m[start] = len + p->second; // append to front
385 if (pstart)
386 *pstart = start;
387 if (plen)
388 *plen = len + p->second;
389 m.erase(p);
390 } else {
391 assert(p->first > start+len);
392 m[start] = len; // new interval
393 if (pstart)
394 *pstart = start;
395 if (plen)
396 *plen = len;
397 }
398 }
399 }
400 }
401
402 void swap(interval_set<T>& other) {
403 m.swap(other.m);
404 std::swap(_size, other._size);
405 }
406
407 void erase(iterator &i) {
408 _size -= i.get_len();
409 assert(_size >= 0);
410 m.erase(i._iter);
411 }
412
413 void erase(T val) {
414 erase(val, 1);
415 }
416
417 void erase(T start, T len) {
418 typename std::map<T,T>::iterator p = find_inc_m(start);
419
420 _size -= len;
421 assert(_size >= 0);
422
423 assert(p != m.end());
424 assert(p->first <= start);
425
426 T before = start - p->first;
427 assert(p->second >= before+len);
428 T after = p->second - before - len;
429
430 if (before)
431 p->second = before; // shorten bit before
432 else
433 m.erase(p);
434 if (after)
435 m[start+len] = after;
436 }
437
438
439 void subtract(const interval_set &a) {
440 for (typename std::map<T,T>::const_iterator p = a.m.begin();
441 p != a.m.end();
442 p++)
443 erase(p->first, p->second);
444 }
445
446 void insert(const interval_set &a) {
447 for (typename std::map<T,T>::const_iterator p = a.m.begin();
448 p != a.m.end();
449 p++)
450 insert(p->first, p->second);
451 }
452
453
454 void intersection_of(const interval_set &a, const interval_set &b) {
455 assert(&a != this);
456 assert(&b != this);
457 clear();
458
459 typename std::map<T,T>::const_iterator pa = a.m.begin();
460 typename std::map<T,T>::const_iterator pb = b.m.begin();
461
462 while (pa != a.m.end() && pb != b.m.end()) {
463 // passing?
464 if (pa->first + pa->second <= pb->first)
465 { pa++; continue; }
466 if (pb->first + pb->second <= pa->first)
467 { pb++; continue; }
468 T start = MAX(pa->first, pb->first);
469 T en = MIN(pa->first+pa->second, pb->first+pb->second);
470 assert(en > start);
471 insert(start, en-start);
472 if (pa->first+pa->second > pb->first+pb->second)
473 pb++;
474 else
475 pa++;
476 }
477 }
478 void intersection_of(const interval_set& b) {
479 interval_set a;
480 swap(a);
481 intersection_of(a, b);
482 }
483
484 void union_of(const interval_set &a, const interval_set &b) {
485 assert(&a != this);
486 assert(&b != this);
487 clear();
488
489 //cout << "union_of" << endl;
490
491 // a
492 m = a.m;
493 _size = a._size;
494
495 // - (a*b)
496 interval_set ab;
497 ab.intersection_of(a, b);
498 subtract(ab);
499
500 // + b
501 insert(b);
502 return;
503 }
504 void union_of(const interval_set &b) {
505 interval_set a;
506 swap(a);
507 union_of(a, b);
508 }
509 void union_insert(T off, T len) {
510 interval_set a;
511 a.insert(off, len);
512 union_of(a);
513 }
514
515 bool subset_of(const interval_set &big) const {
516 for (typename std::map<T,T>::const_iterator i = m.begin();
517 i != m.end();
518 i++)
519 if (!big.contains(i->first, i->second)) return false;
520 return true;
521 }
522
523 /*
524 * build a subset of @other, starting at or after @start, and including
525 * @len worth of values, skipping holes. e.g.,
526 * span_of([5~10,20~5], 8, 5) -> [8~2,20~3]
527 */
528 void span_of(const interval_set &other, T start, T len) {
529 clear();
530 typename std::map<T,T>::const_iterator p = other.find_inc(start);
531 if (p == other.m.end())
532 return;
533 if (p->first < start) {
534 if (p->first + p->second < start)
535 return;
536 if (p->first + p->second < start + len) {
537 T howmuch = p->second - (start - p->first);
538 insert(start, howmuch);
539 len -= howmuch;
540 p++;
541 } else {
542 insert(start, len);
543 return;
544 }
545 }
546 while (p != other.m.end() && len > 0) {
547 if (p->second < len) {
548 insert(p->first, p->second);
549 len -= p->second;
550 p++;
551 } else {
552 insert(p->first, len);
553 return;
554 }
555 }
556 }
557
558 /*
559 * Move contents of m into another std::map<T,T>. Use that instead of
560 * encoding interval_set into bufferlist then decoding it back into std::map.
561 */
562 void move_into(std::map<T,T>& other) {
563 other = std::move(m);
564 }
565
566private:
567 // data
568 int64_t _size;
569 std::map<T,T> m; // map start -> len
570};
571
572// declare traits explicitly because (1) it's templatized, and (2) we
573// want to include _nohead variants.
574template<typename T>
575struct denc_traits<interval_set<T>> {
576 static constexpr bool supported = true;
577 static constexpr bool bounded = false;
578 static constexpr bool featured = false;
579 static void bound_encode(const interval_set<T>& v, size_t& p) {
580 v.bound_encode(p);
581 }
582 static void encode(const interval_set<T>& v,
583 bufferlist::contiguous_appender& p) {
584 v.encode(p);
585 }
586 static void decode(interval_set<T>& v, bufferptr::iterator& p) {
587 v.decode(p);
588 }
589 static void encode_nohead(const interval_set<T>& v,
590 bufferlist::contiguous_appender& p) {
591 v.encode_nohead(p);
592 }
593 static void decode_nohead(size_t n, interval_set<T>& v,
594 bufferptr::iterator& p) {
595 v.decode_nohead(n, p);
596 }
597};
598
599
600template<class T>
601inline std::ostream& operator<<(std::ostream& out, const interval_set<T> &s) {
602 out << "[";
603 const char *prequel = "";
604 for (typename interval_set<T>::const_iterator i = s.begin();
605 i != s.end();
606 ++i)
607 {
608 out << prequel << i.get_start() << "~" << i.get_len();
609 prequel = ",";
610 }
611 out << "]";
612 return out;
613}
614
615
616#endif