range_set.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #include "range_set.h"
  2. #include <util/generic/algorithm.h>
  3. namespace {
  4. bool ShouldJoin(const TIpAddressRange& lhs, const TIpAddressRange& rhs) {
  5. return lhs.Overlaps(rhs) || lhs.IsConsecutive(rhs);
  6. }
  7. }
  8. bool TIpRangeSet::TRangeLess::operator()(const TIpAddressRange& lhs, const TIpAddressRange& rhs) const {
  9. return *lhs.Begin() < *rhs.Begin();
  10. }
  11. TIpRangeSet::TIpRangeSet() = default;
  12. TIpRangeSet::~TIpRangeSet() = default;
  13. void TIpRangeSet::Add(TIpAddressRange r) {
  14. Y_ENSURE(IsEmpty() || r.Type() == Type(), "Mixing IPv4 and IPv6 ranges is disallowed");
  15. auto lowerIt = Ranges_.lower_bound(r);
  16. // still may overlap the last interval in our tree
  17. if (IsEmpty()) {
  18. Ranges_.insert(r);
  19. return;
  20. } else if (lowerIt == Ranges_.end()) {
  21. if (auto it = Ranges_.rbegin(); ShouldJoin(*it, r)) {
  22. auto unitedRange = it->Union(r);
  23. Ranges_.erase(--it.base());
  24. Ranges_.insert(unitedRange);
  25. } else {
  26. Ranges_.insert(r);
  27. }
  28. return;
  29. }
  30. TIpAddressRange unitedRange{r};
  31. auto joined = lowerIt;
  32. if (lowerIt != Ranges_.begin()) {
  33. if (ShouldJoin(unitedRange, *(--joined))) {
  34. unitedRange = unitedRange.Union(*joined);
  35. } else {
  36. ++joined;
  37. }
  38. }
  39. auto it = lowerIt;
  40. for (; it != Ranges_.end() && ShouldJoin(*it, unitedRange); ++it) {
  41. unitedRange = unitedRange.Union(*it);
  42. }
  43. Ranges_.erase(joined, it);
  44. Ranges_.insert(unitedRange);
  45. }
  46. TIpAddressRange::TIpType TIpRangeSet::Type() const {
  47. return IsEmpty()
  48. ? TIpAddressRange::TIpType::LAST
  49. : Ranges_.begin()->Type();
  50. }
  51. bool TIpRangeSet::IsEmpty() const {
  52. return Ranges_.empty();
  53. }
  54. TIpRangeSet::TIterator TIpRangeSet::Find(TIpv6Address addr) const {
  55. if (IsEmpty() || addr.Type() != Type()) {
  56. return End();
  57. }
  58. auto lowerIt = Ranges_.lower_bound(TIpAddressRange(addr, addr));
  59. if (lowerIt == Ranges_.begin()) {
  60. return lowerIt->Contains(addr)
  61. ? lowerIt
  62. : End();
  63. } else if (lowerIt == Ranges_.end()) {
  64. auto rbegin = Ranges_.crbegin();
  65. return rbegin->Contains(addr)
  66. ? (++rbegin).base()
  67. : End();
  68. } else if (lowerIt->Contains(addr)) {
  69. return lowerIt;
  70. }
  71. --lowerIt;
  72. return lowerIt->Contains(addr)
  73. ? lowerIt
  74. : End();
  75. }
  76. bool TIpRangeSet::Contains(TIpv6Address addr) const {
  77. return Find(addr) != End();
  78. }