diff options
| author | msherbakov <[email protected]> | 2022-02-10 16:49:16 +0300 | 
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:49:16 +0300 | 
| commit | c224a621661ddd69699f9476922eb316607ef57e (patch) | |
| tree | 33f4d878aa0a9faa964005e06bfab0272313aa71 /library/cpp/ipmath/ipmath.cpp | |
| parent | 29d0b2eeae154d04156e0698067c0c21a97ea61d (diff) | |
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/ipmath/ipmath.cpp')
| -rw-r--r-- | library/cpp/ipmath/ipmath.cpp | 708 | 
1 files changed, 354 insertions, 354 deletions
| diff --git a/library/cpp/ipmath/ipmath.cpp b/library/cpp/ipmath/ipmath.cpp index b8cca00c805..ccda3bdc7c3 100644 --- a/library/cpp/ipmath/ipmath.cpp +++ b/library/cpp/ipmath/ipmath.cpp @@ -1,357 +1,357 @@ -#include "ipmath.h" - -namespace { -    constexpr auto IPV4_BITS = 32; -    constexpr auto IPV6_BITS = 128; - -    const ui128 MAX_IPV4_ADDR = Max<ui32>(); -    const ui128 MAX_IPV6_ADDR = Max<ui128>(); - -    TStringBuf TypeToString(TIpv6Address::TIpType type) { -        switch (type) { -            case TIpv6Address::Ipv4: +#include "ipmath.h"  +  +namespace {  +    constexpr auto IPV4_BITS = 32;  +    constexpr auto IPV6_BITS = 128;  +  +    const ui128 MAX_IPV4_ADDR = Max<ui32>();  +    const ui128 MAX_IPV6_ADDR = Max<ui128>();  +  +    TStringBuf TypeToString(TIpv6Address::TIpType type) {  +        switch (type) {  +            case TIpv6Address::Ipv4:                   return TStringBuf("IPv4"); -            case TIpv6Address::Ipv6: +            case TIpv6Address::Ipv6:                   return TStringBuf("IPv6"); -            default: +            default:                   return TStringBuf("UNKNOWN"); -        } -    } - -    size_t MaxPrefixLenForType(TIpv6Address::TIpType type) { -        switch (type) { -            case TIpv6Address::Ipv4: -                return IPV4_BITS; -            case TIpv6Address::Ipv6: -                return IPV6_BITS; -            case TIpv6Address::LAST: -                ythrow yexception() << "invalid type"; -        } -    } - -    template <ui8 ADDR_LEN> -    ui128 LowerBoundForPrefix(ui128 value, ui8 prefixLen) { -        const int shift = ADDR_LEN - prefixLen; -        const ui128 shifted = (shift < 128) ? (ui128{1} << shift) : 0; -        ui128 mask = ~(shifted - 1); -        return value & mask; -    } - -    template <ui8 ADDR_LEN> -    ui128 UpperBoundForPrefix(ui128 value, ui8 prefixLen) { -        const int shift = ADDR_LEN - prefixLen; -        const ui128 shifted = (shift < 128) ? (ui128{1} << shift) : 0; -        ui128 mask = shifted - 1; -        return value | mask; -    } - -    auto LowerBoundForPrefix4 = LowerBoundForPrefix<IPV4_BITS>; -    auto LowerBoundForPrefix6 = LowerBoundForPrefix<IPV6_BITS>; -    auto UpperBoundForPrefix4 = UpperBoundForPrefix<IPV4_BITS>; -    auto UpperBoundForPrefix6 = UpperBoundForPrefix<IPV6_BITS>; - -    TIpv6Address IpFromStringSafe(const TString& s) { -        bool ok{}; -        auto addr = TIpv6Address::FromString(s, ok); -        Y_ENSURE(ok, "Failed to parse an IP address from " << s); -        return addr; -    } - -    /// it's different from TIpv6Address::IsValid for 0.0.0.0 -    bool IsValid(TIpv6Address addr) { -        switch (addr.Type()) { -            case TIpv6Address::Ipv4: -            case TIpv6Address::Ipv6: -                return true; - -            case TIpv6Address::LAST: -                return false; -        } -    } - -    bool HasNext(TIpv6Address addr) { -        switch (addr.Type()) { -            case TIpv6Address::Ipv4: -                return ui128(addr) != MAX_IPV4_ADDR; -            case TIpv6Address::Ipv6: -                return ui128(addr) != MAX_IPV6_ADDR; -            case TIpv6Address::LAST: -                return false; -        } -    } - -    TIpv6Address Next(TIpv6Address addr) { -        return {ui128(addr) + 1, addr.Type()}; -    } -} // namespace - -TIpv6Address LowerBoundForPrefix(TIpv6Address value, ui8 prefixLen) { -    auto type = value.Type(); -    switch (type) { -        case TIpv6Address::Ipv4: -            return {LowerBoundForPrefix4(value, prefixLen), type}; -        case TIpv6Address::Ipv6: -            return {LowerBoundForPrefix6(value, prefixLen), type}; -        default: -            ythrow yexception() << "invalid type"; -    } -} - -TIpv6Address UpperBoundForPrefix(TIpv6Address value, ui8 prefixLen) { -    auto type = value.Type(); -    switch (type) { -        case TIpv6Address::Ipv4: -            return {UpperBoundForPrefix4(value, prefixLen), type}; -        case TIpv6Address::Ipv6: -            return {UpperBoundForPrefix6(value, prefixLen), type}; -        default: -            ythrow yexception() << "invalid type"; -    } -} - -TIpAddressRange::TIpAddressRangeBuilder::operator TIpAddressRange() { -    return Build(); -} - -TIpAddressRange TIpAddressRange::TIpAddressRangeBuilder::Build() { -    return TIpAddressRange{Start_, End_}; -} - -TIpAddressRange::TIpAddressRangeBuilder::TIpAddressRangeBuilder(const TString& from) -    : TIpAddressRangeBuilder{IpFromStringSafe(from)} -{ -} - -TIpAddressRange::TIpAddressRangeBuilder::TIpAddressRangeBuilder(TIpv6Address from) { -    Y_ENSURE_EX(IsValid(from), TInvalidIpRangeException() << "Address " << from.ToString() << " is invalid"); -    Start_ = from; -    End_ = Start_; -} - -TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::To(const TString& to) { -    End_ = IpFromStringSafe(to); -    return *this; -} - -TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::To(TIpv6Address to) { -    Y_ENSURE_EX(IsValid(to), TInvalidIpRangeException() << "Address " << to.ToString() << " is invalid"); -    Start_ = to; -    return *this; -} - -TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::WithPrefix(ui8 len) { -    Y_ENSURE_EX(IsValid(Start_), TInvalidIpRangeException() << "Start value must be set before prefix"); -    const auto type = Start_.Type(); -    const auto maxLen = MaxPrefixLenForType(type); -    Y_ENSURE_EX(len <= maxLen, TInvalidIpRangeException() << "Maximum prefix length for this address type is " -        << maxLen << ", but requested " << (ui32)len); - -    const auto lowerBound = LowerBoundForPrefix(Start_, len); -    Y_ENSURE_EX(Start_ == lowerBound, TInvalidIpRangeException() << "Cannot create IP range from start address " -        << Start_ << " with prefix length " << (ui32)len); - -    End_ = UpperBoundForPrefix(Start_, len); - -    return *this; -} - -void TIpAddressRange::Init(TIpv6Address from, TIpv6Address to) { -    Start_ = from; -    End_ = to; - -    Y_ENSURE_EX(Start_ <= End_, TInvalidIpRangeException() << "Invalid IP address range: from " << Start_ << " to " << End_); -    Y_ENSURE_EX(Start_.Type() == End_.Type(), TInvalidIpRangeException() -        << "Address type mismtach: start address type is " << TypeToString(Start_.Type()) -        << " end type is " << TypeToString(End_.Type())); -} - -TIpAddressRange::TIpAddressRange(TIpv6Address start, TIpv6Address end) { -    Y_ENSURE_EX(IsValid(start), TInvalidIpRangeException() << "start address " << start.ToString() << " is invalid"); -    Y_ENSURE_EX(IsValid(end), TInvalidIpRangeException() << "end address " << end.ToString() << " is invalid"); -    Init(start, end); -} - -TIpAddressRange::TIpAddressRange(const TString& start, const TString& end) { -    auto startAddr = IpFromStringSafe(start); -    auto endAddr = IpFromStringSafe(end); -    Init(startAddr, endAddr); -} - -TIpAddressRange::~TIpAddressRange() { -} - -TIpAddressRange::TIpType TIpAddressRange::Type() const { -    return Start_.Type(); -} - -ui128 TIpAddressRange::Size() const { -    return ui128(End_) - ui128(Start_) + 1; -} - -bool TIpAddressRange::IsSingle() const { -    return Start_ == End_; -} - -bool TIpAddressRange::Contains(const TIpAddressRange& other) const { -    return Start_ <= other.Start_ && End_ >= other.End_; -} - -bool TIpAddressRange::Contains(const TIpv6Address& addr) const { -    return Start_ <= addr && End_ >= addr; -} - -bool TIpAddressRange::Overlaps(const TIpAddressRange& other) const { -    return Start_ <= other.End_ && other.Start_ <= End_; -} - -bool TIpAddressRange::IsConsecutive(const TIpAddressRange& other) const { -    return (HasNext(End_) && Next(End_) == other.Start_) -        || (HasNext(other.End_) && Next(other.End_) == Start_); -} - -TIpAddressRange TIpAddressRange::Union(const TIpAddressRange& other) const { -    Y_ENSURE(IsConsecutive(other) || Overlaps(other), "Can merge only consecutive or overlapping ranges"); -    Y_ENSURE(other.Start_.Type() == Start_.Type(), "Cannot merge ranges of addresses of different types"); - -    auto s = Start_; -    auto e = End_; - -    s = {Min<ui128>(Start_, other.Start_), Start_.Type()}; -    e = {Max<ui128>(End_, other.End_), End_.Type()}; - -    return {s, e}; -} - -TIpAddressRange TIpAddressRange::FromCidrString(const TString& str) { -    if (auto result = TryFromCidrString(str)) { -        return *result; -    } - -    ythrow TInvalidIpRangeException() << "Cannot parse " << str << " as a CIDR string"; -} - -TMaybe<TIpAddressRange> TIpAddressRange::TryFromCidrString(const TString& str) { -    auto idx = str.rfind('/'); -    if (idx == TString::npos) { -        return Nothing(); -    } - -    TStringBuf sb{str}; -    TStringBuf address, prefix; -    sb.SplitAt(idx, address, prefix); -    prefix.Skip(1); - -    ui8 prefixLen{}; -    if (!::TryFromString(prefix, prefixLen)) { -        return Nothing(); -    } - -    return TIpAddressRange::From(TString{address}) -        .WithPrefix(prefixLen); -} - -TIpAddressRange TIpAddressRange::FromRangeString(const TString& str) { -    if (auto result = TryFromRangeString(str)) { -        return *result; -    } - -    ythrow TInvalidIpRangeException() << "Cannot parse " << str << " as a range string"; -} - -TMaybe<TIpAddressRange> TIpAddressRange::TryFromRangeString(const TString& str) { -    auto idx = str.find('-'); -    if (idx == TString::npos) { -        return Nothing(); -    } - -    TStringBuf sb{str}; -    TStringBuf start, end; -    sb.SplitAt(idx, start, end); -    end.Skip(1); - -    return TIpAddressRange::From(TString{start}).To(TString{end}); -} - -TIpAddressRange TIpAddressRange::FromString(const TString& str) { -    if (auto result = TryFromString(str)) { -        return *result; -    } - -    ythrow TInvalidIpRangeException() << "Cannot parse an IP address from " << str; -} - -TMaybe<TIpAddressRange> TIpAddressRange::TryFromString(const TString& str) { -    if (auto idx = str.find('/'); idx != TString::npos) { -        return TryFromCidrString(str); -    } else if (idx = str.find('-'); idx != TString::npos) { -        return TryFromRangeString(str); -    } else { -        bool ok{}; -        auto addr = TIpv6Address::FromString(str, ok); -        if (!ok) { -            return Nothing(); -        } - -        return TIpAddressRange::From(addr); -    } -} - -TString TIpAddressRange::ToRangeString() const { -    bool ok{}; -    return TStringBuilder() << Start_.ToString(ok) << "-" << End_.ToString(ok); -} - -TIpAddressRange::TIterator TIpAddressRange::begin() const { -    return Begin(); -} - -TIpAddressRange::TIterator TIpAddressRange::Begin() const { -    return TIpAddressRange::TIterator{Start_}; -} - -TIpAddressRange::TIterator TIpAddressRange::end() const { -    return End(); -} - -TIpAddressRange::TIterator TIpAddressRange::End() const { -    return TIpAddressRange::TIterator{{ui128(End_) + 1, End_.Type()}}; -} - -TIpAddressRange::TIpAddressRangeBuilder TIpAddressRange::From(TIpv6Address from) { -    return TIpAddressRangeBuilder{from}; -}; - -TIpAddressRange::TIpAddressRangeBuilder TIpAddressRange::From(const TString& from) { -    return TIpAddressRangeBuilder{from}; -}; - -bool operator==(const TIpAddressRange& lhs, const TIpAddressRange& rhs) { -    return lhs.Start_ == rhs.Start_ && lhs.End_ == rhs.End_; -} - -bool operator!=(const TIpAddressRange& lhs, const TIpAddressRange& rhs) { -    return !(lhs == rhs); -} - -TIpAddressRange::TIterator::TIterator(TIpv6Address val) noexcept -    : Current_{val} -{ -} - -bool TIpAddressRange::TIterator::operator==(const TIpAddressRange::TIterator& other) noexcept { -    return Current_ == other.Current_; -} - -bool TIpAddressRange::TIterator::operator!=(const TIpAddressRange::TIterator& other) noexcept { -    return !(*this == other); -} - -TIpAddressRange::TIterator& TIpAddressRange::TIterator::operator++() noexcept { -    ui128 numeric = Current_; -    Current_ = {numeric + 1, Current_.Type()}; -    return *this; -} - -const TIpv6Address& TIpAddressRange::TIterator::operator*() noexcept { -    return Current_; -} +        }  +    }  +  +    size_t MaxPrefixLenForType(TIpv6Address::TIpType type) {  +        switch (type) {  +            case TIpv6Address::Ipv4:  +                return IPV4_BITS;  +            case TIpv6Address::Ipv6:  +                return IPV6_BITS;  +            case TIpv6Address::LAST:  +                ythrow yexception() << "invalid type";  +        }  +    }  +  +    template <ui8 ADDR_LEN>  +    ui128 LowerBoundForPrefix(ui128 value, ui8 prefixLen) {  +        const int shift = ADDR_LEN - prefixLen;  +        const ui128 shifted = (shift < 128) ? (ui128{1} << shift) : 0;  +        ui128 mask = ~(shifted - 1);  +        return value & mask;  +    }  +  +    template <ui8 ADDR_LEN>  +    ui128 UpperBoundForPrefix(ui128 value, ui8 prefixLen) {  +        const int shift = ADDR_LEN - prefixLen;  +        const ui128 shifted = (shift < 128) ? (ui128{1} << shift) : 0;  +        ui128 mask = shifted - 1;  +        return value | mask;  +    }  +  +    auto LowerBoundForPrefix4 = LowerBoundForPrefix<IPV4_BITS>;  +    auto LowerBoundForPrefix6 = LowerBoundForPrefix<IPV6_BITS>;  +    auto UpperBoundForPrefix4 = UpperBoundForPrefix<IPV4_BITS>;  +    auto UpperBoundForPrefix6 = UpperBoundForPrefix<IPV6_BITS>;  +  +    TIpv6Address IpFromStringSafe(const TString& s) {  +        bool ok{};  +        auto addr = TIpv6Address::FromString(s, ok);  +        Y_ENSURE(ok, "Failed to parse an IP address from " << s);  +        return addr;  +    }  +  +    /// it's different from TIpv6Address::IsValid for 0.0.0.0  +    bool IsValid(TIpv6Address addr) {  +        switch (addr.Type()) {  +            case TIpv6Address::Ipv4:  +            case TIpv6Address::Ipv6:  +                return true;  +  +            case TIpv6Address::LAST:  +                return false;  +        }  +    }  +  +    bool HasNext(TIpv6Address addr) {  +        switch (addr.Type()) {  +            case TIpv6Address::Ipv4:  +                return ui128(addr) != MAX_IPV4_ADDR;  +            case TIpv6Address::Ipv6:  +                return ui128(addr) != MAX_IPV6_ADDR;  +            case TIpv6Address::LAST:  +                return false;  +        }  +    }  +  +    TIpv6Address Next(TIpv6Address addr) {  +        return {ui128(addr) + 1, addr.Type()};  +    }  +} // namespace  +  +TIpv6Address LowerBoundForPrefix(TIpv6Address value, ui8 prefixLen) {  +    auto type = value.Type();  +    switch (type) {  +        case TIpv6Address::Ipv4:  +            return {LowerBoundForPrefix4(value, prefixLen), type};  +        case TIpv6Address::Ipv6:  +            return {LowerBoundForPrefix6(value, prefixLen), type};  +        default:  +            ythrow yexception() << "invalid type";  +    }  +}  +  +TIpv6Address UpperBoundForPrefix(TIpv6Address value, ui8 prefixLen) {  +    auto type = value.Type();  +    switch (type) {  +        case TIpv6Address::Ipv4:  +            return {UpperBoundForPrefix4(value, prefixLen), type};  +        case TIpv6Address::Ipv6:  +            return {UpperBoundForPrefix6(value, prefixLen), type};  +        default:  +            ythrow yexception() << "invalid type";  +    }  +}  +  +TIpAddressRange::TIpAddressRangeBuilder::operator TIpAddressRange() {  +    return Build();  +}  +  +TIpAddressRange TIpAddressRange::TIpAddressRangeBuilder::Build() {  +    return TIpAddressRange{Start_, End_};  +}  +  +TIpAddressRange::TIpAddressRangeBuilder::TIpAddressRangeBuilder(const TString& from)  +    : TIpAddressRangeBuilder{IpFromStringSafe(from)}  +{  +}  +  +TIpAddressRange::TIpAddressRangeBuilder::TIpAddressRangeBuilder(TIpv6Address from) {  +    Y_ENSURE_EX(IsValid(from), TInvalidIpRangeException() << "Address " << from.ToString() << " is invalid");  +    Start_ = from;  +    End_ = Start_;  +}  +  +TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::To(const TString& to) {  +    End_ = IpFromStringSafe(to);  +    return *this;  +}  +  +TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::To(TIpv6Address to) {  +    Y_ENSURE_EX(IsValid(to), TInvalidIpRangeException() << "Address " << to.ToString() << " is invalid");  +    Start_ = to;  +    return *this;  +}  +  +TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::WithPrefix(ui8 len) {  +    Y_ENSURE_EX(IsValid(Start_), TInvalidIpRangeException() << "Start value must be set before prefix");  +    const auto type = Start_.Type();  +    const auto maxLen = MaxPrefixLenForType(type);  +    Y_ENSURE_EX(len <= maxLen, TInvalidIpRangeException() << "Maximum prefix length for this address type is "  +        << maxLen << ", but requested " << (ui32)len);  +  +    const auto lowerBound = LowerBoundForPrefix(Start_, len);  +    Y_ENSURE_EX(Start_ == lowerBound, TInvalidIpRangeException() << "Cannot create IP range from start address "  +        << Start_ << " with prefix length " << (ui32)len);  +  +    End_ = UpperBoundForPrefix(Start_, len);  +  +    return *this;  +}  +  +void TIpAddressRange::Init(TIpv6Address from, TIpv6Address to) {  +    Start_ = from;  +    End_ = to;  +  +    Y_ENSURE_EX(Start_ <= End_, TInvalidIpRangeException() << "Invalid IP address range: from " << Start_ << " to " << End_);  +    Y_ENSURE_EX(Start_.Type() == End_.Type(), TInvalidIpRangeException()  +        << "Address type mismtach: start address type is " << TypeToString(Start_.Type())  +        << " end type is " << TypeToString(End_.Type()));  +}  +  +TIpAddressRange::TIpAddressRange(TIpv6Address start, TIpv6Address end) {  +    Y_ENSURE_EX(IsValid(start), TInvalidIpRangeException() << "start address " << start.ToString() << " is invalid");  +    Y_ENSURE_EX(IsValid(end), TInvalidIpRangeException() << "end address " << end.ToString() << " is invalid");  +    Init(start, end);  +}  +  +TIpAddressRange::TIpAddressRange(const TString& start, const TString& end) {  +    auto startAddr = IpFromStringSafe(start);  +    auto endAddr = IpFromStringSafe(end);  +    Init(startAddr, endAddr);  +}  +  +TIpAddressRange::~TIpAddressRange() {  +}  +  +TIpAddressRange::TIpType TIpAddressRange::Type() const {  +    return Start_.Type();  +}  +  +ui128 TIpAddressRange::Size() const {  +    return ui128(End_) - ui128(Start_) + 1;  +}  +  +bool TIpAddressRange::IsSingle() const {  +    return Start_ == End_;  +}  +  +bool TIpAddressRange::Contains(const TIpAddressRange& other) const {  +    return Start_ <= other.Start_ && End_ >= other.End_;  +}  +  +bool TIpAddressRange::Contains(const TIpv6Address& addr) const {  +    return Start_ <= addr && End_ >= addr;  +}  +  +bool TIpAddressRange::Overlaps(const TIpAddressRange& other) const {  +    return Start_ <= other.End_ && other.Start_ <= End_;  +}  +  +bool TIpAddressRange::IsConsecutive(const TIpAddressRange& other) const {  +    return (HasNext(End_) && Next(End_) == other.Start_)  +        || (HasNext(other.End_) && Next(other.End_) == Start_);  +}  +  +TIpAddressRange TIpAddressRange::Union(const TIpAddressRange& other) const {  +    Y_ENSURE(IsConsecutive(other) || Overlaps(other), "Can merge only consecutive or overlapping ranges");  +    Y_ENSURE(other.Start_.Type() == Start_.Type(), "Cannot merge ranges of addresses of different types");  +  +    auto s = Start_;  +    auto e = End_;  +  +    s = {Min<ui128>(Start_, other.Start_), Start_.Type()};  +    e = {Max<ui128>(End_, other.End_), End_.Type()};  +  +    return {s, e};  +}  +  +TIpAddressRange TIpAddressRange::FromCidrString(const TString& str) {  +    if (auto result = TryFromCidrString(str)) {  +        return *result;  +    }  +  +    ythrow TInvalidIpRangeException() << "Cannot parse " << str << " as a CIDR string";  +}  +  +TMaybe<TIpAddressRange> TIpAddressRange::TryFromCidrString(const TString& str) {  +    auto idx = str.rfind('/');  +    if (idx == TString::npos) {  +        return Nothing();  +    }  +  +    TStringBuf sb{str};  +    TStringBuf address, prefix;  +    sb.SplitAt(idx, address, prefix);  +    prefix.Skip(1);  +  +    ui8 prefixLen{};  +    if (!::TryFromString(prefix, prefixLen)) {  +        return Nothing();  +    }  +  +    return TIpAddressRange::From(TString{address})  +        .WithPrefix(prefixLen);  +}  +  +TIpAddressRange TIpAddressRange::FromRangeString(const TString& str) {  +    if (auto result = TryFromRangeString(str)) {  +        return *result;  +    }  +  +    ythrow TInvalidIpRangeException() << "Cannot parse " << str << " as a range string";  +}  +  +TMaybe<TIpAddressRange> TIpAddressRange::TryFromRangeString(const TString& str) {  +    auto idx = str.find('-');  +    if (idx == TString::npos) {  +        return Nothing();  +    }  +  +    TStringBuf sb{str};  +    TStringBuf start, end;  +    sb.SplitAt(idx, start, end);  +    end.Skip(1);  +  +    return TIpAddressRange::From(TString{start}).To(TString{end});  +}  +  +TIpAddressRange TIpAddressRange::FromString(const TString& str) {  +    if (auto result = TryFromString(str)) {  +        return *result;  +    }  +  +    ythrow TInvalidIpRangeException() << "Cannot parse an IP address from " << str;  +}  +  +TMaybe<TIpAddressRange> TIpAddressRange::TryFromString(const TString& str) {  +    if (auto idx = str.find('/'); idx != TString::npos) {  +        return TryFromCidrString(str);  +    } else if (idx = str.find('-'); idx != TString::npos) {  +        return TryFromRangeString(str);  +    } else {  +        bool ok{};  +        auto addr = TIpv6Address::FromString(str, ok);  +        if (!ok) {  +            return Nothing();  +        }  +  +        return TIpAddressRange::From(addr);  +    }  +}  +  +TString TIpAddressRange::ToRangeString() const {  +    bool ok{};  +    return TStringBuilder() << Start_.ToString(ok) << "-" << End_.ToString(ok);  +}  +  +TIpAddressRange::TIterator TIpAddressRange::begin() const {  +    return Begin();  +}  +  +TIpAddressRange::TIterator TIpAddressRange::Begin() const {  +    return TIpAddressRange::TIterator{Start_};  +}  +  +TIpAddressRange::TIterator TIpAddressRange::end() const {  +    return End();  +}  +  +TIpAddressRange::TIterator TIpAddressRange::End() const {  +    return TIpAddressRange::TIterator{{ui128(End_) + 1, End_.Type()}};  +}  +  +TIpAddressRange::TIpAddressRangeBuilder TIpAddressRange::From(TIpv6Address from) {  +    return TIpAddressRangeBuilder{from};  +};  +  +TIpAddressRange::TIpAddressRangeBuilder TIpAddressRange::From(const TString& from) {  +    return TIpAddressRangeBuilder{from};  +};  +  +bool operator==(const TIpAddressRange& lhs, const TIpAddressRange& rhs) {  +    return lhs.Start_ == rhs.Start_ && lhs.End_ == rhs.End_;  +}  +  +bool operator!=(const TIpAddressRange& lhs, const TIpAddressRange& rhs) {  +    return !(lhs == rhs);  +}  +  +TIpAddressRange::TIterator::TIterator(TIpv6Address val) noexcept  +    : Current_{val}  +{  +}  +  +bool TIpAddressRange::TIterator::operator==(const TIpAddressRange::TIterator& other) noexcept {  +    return Current_ == other.Current_;  +}  +  +bool TIpAddressRange::TIterator::operator!=(const TIpAddressRange::TIterator& other) noexcept {  +    return !(*this == other);  +}  +  +TIpAddressRange::TIterator& TIpAddressRange::TIterator::operator++() noexcept {  +    ui128 numeric = Current_;  +    Current_ = {numeric + 1, Current_.Type()};  +    return *this;  +}  +  +const TIpv6Address& TIpAddressRange::TIterator::operator*() noexcept {  +    return Current_;  +}  | 
