This is an automated email from the ASF dual-hosted git repository. bneradt pushed a commit to branch github-build in repository https://gitbox.apache.org/repos/asf/trafficserver-libswoc.git
commit 3b300250e02de64b2981e75a00aaf874366813b3 Author: Alan M. Carroll <[email protected]> AuthorDate: Sun Jun 4 10:02:21 2023 -0500 IPSpace: update to use struct instead of tuple. --- code/include/swoc/IPRange.h | 335 ++++++++++++++++++++++++++---------- code/include/swoc/Lexicon.h | 2 +- unit_tests/ex_Lexicon.cc | 4 +- unit_tests/ex_ipspace_properties.cc | 4 +- unit_tests/test_ip.cc | 110 ++++++------ 5 files changed, 301 insertions(+), 154 deletions(-) diff --git a/code/include/swoc/IPRange.h b/code/include/swoc/IPRange.h index aa93d17..cf9b66c 100644 --- a/code/include/swoc/IPRange.h +++ b/code/include/swoc/IPRange.h @@ -8,22 +8,19 @@ #include <string_view> #include <variant> // for std::monostate +#include <tuple> #include <swoc/DiscreteRange.h> #include <swoc/IPAddr.h> namespace swoc { inline namespace SWOC_VERSION_NS { -using ::std::string_view; +using std::string_view; class IP4Net; class IP6Net; class IPNet; -namespace detail { -extern void *const pseudo_nullptr; -} - /** An inclusive range of IPv4 addresses. */ class IP4Range : public DiscreteRange<IP4Addr> { @@ -335,6 +332,7 @@ public: * @param max Maximum range value. */ IPRange(IP4Addr const &min, IP4Addr const &max); + /** Construct an inclusive range. * * @param min Minimum range value. @@ -346,8 +344,8 @@ public: * * @param addr Address of range. */ - IPRange(IPAddr const& addr) : IPRange(addr, addr) {} + /** Construct a singleton range. * * @param addr Address of range. @@ -366,7 +364,6 @@ public: /// Construct from an IPv6 @a range. IPRange(IP6Range const &range); - /** Construct from a string format. * * @param text Text form of range. @@ -384,16 +381,10 @@ public: bool operator!=(self_type const& that) const; /// @return @c true if this is an IPv4 range, @c false if not. - bool - is_ip4() const { - return AF_INET == _family; - } + bool is_ip4() const; /// @return @c true if this is an IPv6 range, @c false if not. - bool - is_ip6() const { - return AF_INET6 == _family; - } + bool is_ip6() const; /** Check if @a this range is the IP address @a family. * @@ -421,6 +412,9 @@ public: /// @return @c true if there are no addresses in the range. bool empty() const; + /// Make the range empty / invalid. + self_type & clear(); + /// @return The IPv4 range. IP4Range const & ip4() const { return _range._ip4; } @@ -438,6 +432,7 @@ public: */ IPMask network_mask() const; + /// Container for remaining range for network generation. class NetSource; /** Generate a list of networks covering @a this range. @@ -473,6 +468,7 @@ protected: IP4Range _ip4; ///< IPv4 range. IP6Range _ip6; ///< IPv6 range. } _range{std::monostate{}}; + /// Family of @a _range. sa_family_t _family{AF_UNSPEC}; }; @@ -533,6 +529,7 @@ protected: IP4Range::NetSource _ip4; ///< IPv4 addresses. IP6Range::NetSource _ip6; ///< IPv6 addresses. }; + sa_family_t _family = AF_UNSPEC; ///< Mark for union content. }; @@ -730,21 +727,20 @@ public: /// @return A range that exactly covers the network. IPRange as_range() const; + /// @return @c true if network is IPv4. bool is_ip4() const { return _addr.is_ip4(); } + /// @return @c true if network is IPv6. bool is_ip6() const { return _addr.is_ip6(); } + /// Address family of network. sa_family_t family() const { return _addr.family(); } - IP4Net - ip4() const { - return IP4Net{_addr.ip4(), _mask}; - } + /// @return The network as explicitly IPv4. + IP4Net ip4() const; - IP6Net - ip6() const { - return IP6Net{_addr.ip6(), _mask}; - } + /// @return The network as explicitly IPv6. + IP6Net ip6() const; /** Assign an @a addr and @a mask to @a this. * @@ -755,11 +751,7 @@ public: self_type &assign(IPAddr const &addr, IPMask const &mask); /// Reset network to invalid state. - self_type & - clear() { - _mask.clear(); - return *this; - } + self_type & clear(); /// Equality. bool operator==(self_type const &that) const; @@ -773,6 +765,105 @@ protected: }; // -------------------------------------------------------------------------- +namespace detail { +/** Value type for @c IPSpace. + * + * @tparam PAYLOAD User data type to be stored. + * + * @internal Exported because inner classes in template classes cannot be used in partial + * specialization which is required for tuple support. This should be removed next API incompatible + * change release because tuple access is being deprecated. + * + * @note The @c assign methods are used to update iterators. + * + * @see IPSpace + */ +template < typename PAYLOAD > struct ip_space_value_type { + using self_type = ip_space_value_type; + + swoc::IPRange _range; ///< Address range. + PAYLOAD * _payload = nullptr; ///< Payload for @a _range. + + /// @return The address range. + swoc::IPRange const & range() const { return _range; } + /// @return A reference to the payload (user content). + PAYLOAD const & payload() const { return *_payload; } + /// @return A reference to the payload (user content). + PAYLOAD & payload() { return *_payload; } + + /// Reset to default constructed state. + self_type & clear(); + + /** Update the internal state. + * + * @param r Range. + * @param payload Payload. + * @return @a this. + */ + self_type & assign(swoc::IP4Range const& r, PAYLOAD & payload); + + /** Update the internal state. + * + * @param r Range. + * @param payload Payload. + * @return @a this. + */ + self_type & assign(swoc::IP6Range const& r, PAYLOAD & payload); + + /** Update from another instance. + * + * @param that Other instance. + * @return @a this. + */ + self_type & assign(self_type const& that); + + /// Support assignemnt to @c std::tie. + operator std::tuple<swoc::IPRange &, PAYLOAD &> () { return { _range, *_payload }; } + + /// Equality against an equivalent tuple. + bool operator == (std::tuple<swoc::IPRange, PAYLOAD> const& t) const; +}; + +template <typename PAYLOAD> +auto +ip_space_value_type<PAYLOAD>::clear() -> self_type & { + _range.clear(); + _payload = nullptr; + return *this; +} + +template <typename PAYLOAD> +auto +ip_space_value_type<PAYLOAD>::assign(IP4Range const &r, PAYLOAD &payload) -> self_type &{ + _range = r; + _payload = &payload; + return *this; +} + +template <typename PAYLOAD> +auto +ip_space_value_type<PAYLOAD>::assign(IP6Range const &r, PAYLOAD &payload) -> self_type & { + _range = r; + _payload = &payload; + return *this; +} + +template <typename PAYLOAD> +auto +ip_space_value_type<PAYLOAD>::assign(ip_space_value_type::self_type const &that) -> self_type & { + _range = that._range; + _payload = that._payload; + return *this; +} + +template <typename PAYLOAD> +bool +ip_space_value_type<PAYLOAD>::operator==(std::tuple<swoc::IPRange, PAYLOAD> const &t) const { + return _range == std::get<0>(t) && std::get<1>(t) == *_payload; +} + +} // namespace detail + /** Coloring of IP address space. * * @tparam PAYLOAD The color class. @@ -793,7 +884,8 @@ template <typename PAYLOAD> class IPSpace { public: using payload_t = PAYLOAD; ///< Export payload type. - using value_type = std::tuple<IPRange const, PAYLOAD &>; + /// Iterator value, a range and payload. + using value_type = detail::ip_space_value_type<PAYLOAD>; /// Construct an empty space. IPSpace() = default; @@ -850,8 +942,7 @@ public: self_type & blend(IP4Range const &range, U const &color, F &&blender); template <typename F, typename U = PAYLOAD> - self_type & - blend(IP6Range const &range, U const &color, F &&blender); + self_type & blend(IP6Range const &range, U const &color, F &&blender); /// @return The number of distinct ranges. size_t count() const; @@ -898,7 +989,7 @@ public: friend class IPSpace; public: - using value_type = std::tuple<IPRange const, PAYLOAD const &>; /// Import for API compliance. + using value_type = IPSpace::value_type const; /// Import for API compliance. // STL algorithm compliance. using iterator_category = std::bidirectional_iterator_tag; using pointer = value_type *; @@ -936,31 +1027,11 @@ public: /// Dereference. /// @return A reference to the referent. - value_type operator*() const; + value_type & operator*() const; /// Dereference. /// @return A pointer to the referent. - value_type const *operator->() const; - - /** The range for the iterator. - * - * @return Iterator range. - * - * @note If the iterator is not valid the returned range will be empty. - */ - IPRange const& range() const; - - /** The payload for the iterator. - * - * @return The payload. - * - * @note This yields undetermined results for invalid iterators. Always check for validity befure - * using this method. - * - * @note It is not possible to retrieve a modifiable payload because that can break the internal - * invariant that adjcent ranges always have different payloads. - */ - PAYLOAD const& payload() const; + value_type * operator->() const; /// Equality bool operator==(self_type const &that) const; @@ -977,7 +1048,7 @@ public: typename IP4Space::iterator _iter_4; ///< IPv4 sub-space iterator. typename IP6Space::iterator _iter_6; ///< IPv6 sub-space iterator. /// Current value. - value_type _value{IPRange{}, *static_cast<PAYLOAD *>(detail::pseudo_nullptr)}; + IPSpace::value_type _value; /** Internal constructor. * @@ -1008,7 +1079,7 @@ public: iterator(const_iterator const& that) : const_iterator(that) {} public: /// Value type of iteration. - using value_type = std::tuple<IPRange const, PAYLOAD &>; + using value_type = IPSpace::value_type; using pointer = value_type *; using reference = value_type &; @@ -1034,30 +1105,20 @@ public: /// Post-increment. /// Move to the next element in the list. /// @return The iterator value before the increment. - self_type - operator++(int) { - self_type zret{*this}; - ++*this; - return zret; - } + self_type operator++(int); /// Post-decrement. /// Move to the previous element in the list. /// @return The iterator value before the decrement. - self_type - operator--(int) { - self_type zret{*this}; - --*this; - return zret; - } + self_type operator--(int); /// Dereference. /// @return A reference to the referent. - value_type operator*() const; + reference operator*() const; /// Dereference. /// @return A pointer to the referent. - value_type const *operator->() const; + pointer operator->() const; }; @@ -1376,9 +1437,9 @@ template <typename PAYLOAD> IPSpace<PAYLOAD>::const_iterator::const_iterator(typename IP4Space::iterator const &iter4, typename IP6Space::iterator const &iter6) : _iter_4(iter4), _iter_6(iter6) { if (_iter_4.has_next()) { - new (&_value) value_type{_iter_4->range(), _iter_4->payload()}; + _value.assign(_iter_4->range(), _iter_4->payload()); } else if (_iter_6.has_next()) { - new (&_value) value_type{_iter_6->range(), _iter_6->payload()}; + _value.assign(_iter_6->range(), _iter_6->payload()); } } @@ -1387,7 +1448,7 @@ auto IPSpace<PAYLOAD>::const_iterator::operator=(self_type const &that) -> self_type & { _iter_4 = that._iter_4; _iter_6 = that._iter_6; - new (&_value) value_type{that._value}; + _value.assign(that._value); return *this; } @@ -1399,18 +1460,18 @@ IPSpace<PAYLOAD>::const_iterator::operator++() -> self_type & { ++_iter_4; incr_p = true; if (_iter_4.has_next()) { - new (&_value) value_type{_iter_4->range(), _iter_4->payload()}; + _value.assign(_iter_4->range(), _iter_4->payload()); return *this; } } if (_iter_6.has_next()) { if (incr_p || (++_iter_6).has_next()) { - new (&_value) value_type{_iter_6->range(), _iter_6->payload()}; + _value.assign(_iter_6->range(), _iter_6->payload()); return *this; } } - new (&_value) value_type{IPRange{}, *static_cast<PAYLOAD *>(detail::pseudo_nullptr)}; + _value.clear(); return *this; } @@ -1427,15 +1488,15 @@ auto IPSpace<PAYLOAD>::const_iterator::operator--() -> self_type & { if (_iter_6.has_prev()) { --_iter_6; - new (&_value) value_type{_iter_6->range(), _iter_6->payload()}; + _value.assign(_iter_6->range(), _iter_6->payload()); return *this; } if (_iter_4.has_prev()) { --_iter_4; - new (&_value) value_type{_iter_4->range(), _iter_4->payload()}; + _value.assign(_iter_4->range(), _iter_4->payload()); return *this; } - new (&_value) value_type{IPRange{}, *static_cast<PAYLOAD *>(detail::pseudo_nullptr)}; + _value.clear(); return *this; } @@ -1449,7 +1510,7 @@ IPSpace<PAYLOAD>::const_iterator::operator--(int) -> self_type { template <typename PAYLOAD> auto -IPSpace<PAYLOAD>::const_iterator::operator*() const -> value_type { +IPSpace<PAYLOAD>::const_iterator::operator*() const -> value_type & { return _value; } @@ -1459,14 +1520,6 @@ IPSpace<PAYLOAD>::const_iterator::operator->() const -> value_type const * { return &_value; } -template <typename PAYLOAD> -IPRange const & -IPSpace<PAYLOAD>::const_iterator::range() const { return std::get<0>(_value); } - -template <typename PAYLOAD> -PAYLOAD const & -IPSpace<PAYLOAD>::const_iterator::payload() const { return std::get<1>(_value); } - /* Bit of subtlety with equality - although it seems that if @a _iter_4 is valid, it doesn't matter * where @a _iter6 is (because it is really the iterator location that's being checked), it's * necessary to do the @a _iter_4 validity on both iterators to avoid the case of a false positive @@ -1496,14 +1549,14 @@ IPSpace<PAYLOAD>::iterator::operator=(self_type const &that) -> self_type & { template <typename PAYLOAD> auto -IPSpace<PAYLOAD>::iterator::operator->() const -> value_type const * { - return static_cast<value_type *>(&super_type::_value); +IPSpace<PAYLOAD>::iterator::operator->() const -> pointer { + return & const_cast<self_type*>(this)->_value; } template <typename PAYLOAD> auto -IPSpace<PAYLOAD>::iterator::operator*() const -> value_type { - return reinterpret_cast<value_type const &>(super_type::_value); +IPSpace<PAYLOAD>::iterator::operator*() const -> reference { + return const_cast<self_type*>(this)->_value; } template <typename PAYLOAD> @@ -1513,6 +1566,14 @@ IPSpace<PAYLOAD>::iterator::operator++() -> self_type & { return *this; } +template <typename PAYLOAD> +auto +IPSpace<PAYLOAD>::iterator::operator++(int) -> self_type { + self_type zret{*this}; + ++*this; + return zret; +} + template <typename PAYLOAD> auto IPSpace<PAYLOAD>::iterator::operator--() -> self_type & { @@ -1520,7 +1581,14 @@ IPSpace<PAYLOAD>::iterator::operator--() -> self_type & { return *this; } -// -------------------------------------------------------------------------- +template <typename PAYLOAD> +auto +IPSpace<PAYLOAD>::iterator::operator--(int) -> self_type { + self_type zret{*this}; + --*this; + return zret; +} + /// ------------------------------------------------------------------------------------ // +++ IPRange +++ @@ -1577,6 +1645,12 @@ IPRange::assign(IP6Addr const &min, IP6Addr const &max) -> self_type & { return *this; } +inline auto +IPRange::clear() -> self_type & { + _family = AF_UNSPEC; + return *this; +} + inline auto IPRange::networks() const -> NetSource { return {NetSource{*this}}; @@ -1592,6 +1666,15 @@ IPRange::operator!=(const self_type &that) const { return ! (*this == that); } +inline bool +IPRange::is_ip4() const { + return AF_INET == _family; +} + +inline bool IPRange::is_ip6() const { + return AF_INET6 == _family; +} + // +++ IPNet +++ inline IP4Net::IP4Net(swoc::IP4Addr addr, swoc::IPMask mask) : _addr(addr & mask), _mask(mask) {} @@ -1771,6 +1854,22 @@ operator==(IP6Net const &lhs, IPNet const &rhs) { return rhs.is_ip6() && rhs.ip6() == lhs; } +inline IP4Net +IPNet::ip4() const { + return IP4Net{_addr.ip4(), _mask}; +} + +inline IP6Net +IPNet::ip6() const { + return IP6Net{_addr.ip6(), _mask}; +} + +inline auto +IPNet::clear() -> self_type & { + _mask.clear(); + return *this; +} + // +++ Range -> Network classes +++ inline bool @@ -2180,12 +2279,12 @@ IPRangeSet::const_iterator::operator--(int) -> self_type { inline auto IPRangeSet::const_iterator::operator*() const -> value_type const& { - return _iter.range(); + return _iter->range(); } inline auto IPRangeSet::const_iterator::operator->() const -> value_type const * { - return &(_iter.range()); + return &(_iter->range()); } inline bool @@ -2284,3 +2383,49 @@ get(swoc::IPNet const &net) { /// @endcond }} // namespace swoc::SWOC_VERSION_NS + +// Tuple support for IPSpace values. +/// @cond NOT_DOCUMENTED + +namespace std { + +template <typename P> class tuple_size<swoc::detail::ip_space_value_type<P>> : public integral_constant<size_t, 2> {}; + +template <size_t IDX, typename P> class tuple_element<IDX, swoc::detail::ip_space_value_type<P>> { + static_assert("swoc::IPSpace::value_type tuple index out of range"); +}; + +template <typename P> class tuple_element<0, swoc::detail::ip_space_value_type<P>> { +public: + using type = swoc::IPRange const &; +}; + +template <typename P> class tuple_element<1, swoc::detail::ip_space_value_type<P>> { +public: + using type = P &; +}; + +} // namespace std + +namespace swoc { inline namespace SWOC_VERSION_NS { namespace detail { +template <size_t IDX, typename P> +auto +get(ip_space_value_type<P> const &p) -> typename std::tuple_element<IDX, ip_space_value_type<P>>::type { + if constexpr (IDX == 0) { + return p._range; + } else if constexpr (IDX == 1) { + // Apparently some compilers complain because this can be @c nullptr but that's a valid state. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + return *(p._payload); + #pragma GCC diagnostic pop + } +} +}}} // namespace swoc::detail + +// Support unqualified @c get because ADL doesn't seem to work. +using swoc::detail::get; +// Support @c std::get +namespace std { using swoc::detail::get; } + +/// @endcond diff --git a/code/include/swoc/Lexicon.h b/code/include/swoc/Lexicon.h index c81337f..166cb6f 100644 --- a/code/include/swoc/Lexicon.h +++ b/code/include/swoc/Lexicon.h @@ -39,7 +39,7 @@ what(std::string_view const &fmt, Args &&...args) { } // Exported because inner classes in template classes cannot be used in partial specialization -// which is required for tuple support. This should be remove next time there is a API changing +// which is required for tuple support. This should be removed next time there is a API changing // release because tuple access is being deprecated. template < typename E > struct lexicon_pair_type { E _value; diff --git a/unit_tests/ex_Lexicon.cc b/unit_tests/ex_Lexicon.cc index 34281a7..a2ab2cc 100644 --- a/unit_tests/ex_Lexicon.cc +++ b/unit_tests/ex_Lexicon.cc @@ -86,7 +86,7 @@ TEST_CASE("Lexicon Example", "[libts][Lexicon]") { for ( auto const& [ addr, bits ] : AddrList ) { // doc.lookup.begin - auto && [ range, flags ] = *space.find(addr); + auto const& [ range, flags ] = *space.find(addr); // doc.lookup.end REQUIRE(flags == bits); } @@ -100,7 +100,7 @@ swoc::Lexicon<NetType> const Example1 { {NetType::PROD, "prod"}, {NetType::SECURE, "secure"}, {NetType::EDGE, "edge"}}, -"*invalid*", // default name for undefined values + "*invalid*", // default name for undefined values NetType::INVALID // default value for undefined name }; // doc.ctor.1.end diff --git a/unit_tests/ex_ipspace_properties.cc b/unit_tests/ex_ipspace_properties.cc index d98ef11..7d610c2 100644 --- a/unit_tests/ex_ipspace_properties.cc +++ b/unit_tests/ex_ipspace_properties.cc @@ -58,7 +58,7 @@ TEST_CASE("IPSpace bitset blending", "[libswoc][ipspace][bitset][blending]") { auto dump = [](Space&space) -> void { if (Verbose_p) { std::cout << W().print("{} ranges\n", space.count()); - for (auto &&[r, payload] : space) { + for (auto && [r, payload] : space) { std::cout << W().print("{:25} : {}\n", r, payload); } } @@ -411,7 +411,7 @@ bool Table::parse(TextView src) { auto Table::find(IPAddr const &addr) -> Row * { auto spot = _space.find(addr); - return spot == _space.end() ? nullptr : &std::get<1>(*spot); + return spot == _space.end() ? nullptr : &(spot->payload()); } bool operator == (Table::Row const&, Table::Row const&) { return false; } diff --git a/unit_tests/test_ip.cc b/unit_tests/test_ip.cc index 711428e..0df4b42 100644 --- a/unit_tests/test_ip.cc +++ b/unit_tests/test_ip.cc @@ -38,12 +38,13 @@ using swoc::IP6Net; using swoc::IPSpace; using swoc::IPRangeSet; -using W = swoc::LocalBufferWriter<256>; namespace { +std::string bws; + template<typename P> void dump(IPSpace < P > const& space) { for ( auto && [ r, p ] : space ) { - std::cout << W().print("{} : {}\n", r, p).view(); + std::cout << bwprint(bws, "{} : {}\n", r, p); } } } // namespace @@ -347,54 +348,56 @@ TEST_CASE("Basic IP", "[libswoc][ip]") { }; TEST_CASE("IP Net and Mask", "[libswoc][ip][ipnet]") { - IP4Addr a24{"255.255.255.0"}; - REQUIRE(IP4Addr::MAX == IPMask(32).as_ip4()); - REQUIRE(IP4Addr::MIN == IPMask(0).as_ip4()); - REQUIRE(IPMask(24).as_ip4() == a24); - - swoc::IP4Net n1{"0/1"}; - auto nr1 = n1.as_range(); - REQUIRE(nr1.min() == IP4Addr::MIN); - REQUIRE(nr1.max() == IP4Addr("127.255.255.255")); - - IP4Addr a{"8.8.8.8"}; - swoc::IP4Net n4{a, IPMask{32}}; - auto nr4 = n4.as_range(); - REQUIRE(nr4.min() == a); - REQUIRE(nr4.max() == a); - - swoc::IP4Net n0{"0/0"}; - auto nr0 = n0.as_range(); - REQUIRE(nr0.min() == IP4Addr::MIN); - REQUIRE(nr0.max() == IP4Addr::MAX); - - swoc::IPMask m128{128}; - REQUIRE(m128.as_ip6() == IP6Addr::MAX); - swoc::IPMask m0{0}; - REQUIRE(m0.as_ip6() == IP6Addr::MIN); - - IP6Addr a6{"12:34:56:78:9A:BC:DE:FF"}; - REQUIRE(a6 == (a6 | IPMask(0))); - REQUIRE(IP6Addr::MAX == (a6 | IPMask(IP6Addr::WIDTH))); - REQUIRE(IP6Addr::MIN == (a6 & IPMask(0))); - - IP6Addr a6_2{"2001:1f2d:c587:24c3:9128:3349:3cee:143"_tv}; - swoc::IPMask mask{127}; - CHECK(a6_2 == (a6_2 | mask)); - CHECK(a6_2 != (a6_2 & mask)); - CHECK(a6_2 == (a6_2 & swoc::IPMask(128))); // should always be a no-op. - - IP6Net n6_1{a6_2, IPMask(96)}; - CHECK(n6_1.min() == IP6Addr("2001:1f2d:c587:24c3:9128:3349::")); - - swoc::IP6Addr a6_3{"2001:1f2d:c587:24c4::"}; - CHECK(a6_3 == (a6_3 & swoc::IPMask{64})); - CHECK(a6_3 == (a6_3 & swoc::IPMask{62})); - CHECK(a6_3 != (a6_3 & swoc::IPMask{61})); - - REQUIRE(IPMask(1) == IPMask::mask_for(IP4Addr("0x80.0.0.0"))); - REQUIRE(IPMask(2) == IPMask::mask_for(IP4Addr("0xC0.0.0.0"))); - REQUIRE(IPMask(27) == IPMask::mask_for(IP4Addr("0xFF.0xFF.0xFF.0xE0"))); + IP4Addr a24{"255.255.255.0"}; + REQUIRE(IP4Addr::MAX == IPMask(32).as_ip4()); + REQUIRE(IP4Addr::MIN == IPMask(0).as_ip4()); + REQUIRE(IPMask(24).as_ip4() == a24); + + swoc::IP4Net n1{"0/1"}; + auto nr1 = n1.as_range(); + REQUIRE(nr1.min() == IP4Addr::MIN); + REQUIRE(nr1.max() == IP4Addr("127.255.255.255")); + + IP4Addr a{"8.8.8.8"}; + swoc::IP4Net n4{a, IPMask{32}}; + auto nr4 = n4.as_range(); + REQUIRE(nr4.min() == a); + REQUIRE(nr4.max() == a); + + swoc::IP4Net n0{"0/0"}; + auto nr0 = n0.as_range(); + REQUIRE(nr0.min() == IP4Addr::MIN); + REQUIRE(nr0.max() == IP4Addr::MAX); + + swoc::IPMask m128{128}; + REQUIRE(m128.as_ip6() == IP6Addr::MAX); + swoc::IPMask m0{0}; + REQUIRE(m0.as_ip6() == IP6Addr::MIN); + + IP6Addr a6{"12:34:56:78:9A:BC:DE:FF"}; + REQUIRE(a6 == (a6 | IPMask(0))); + REQUIRE(IP6Addr::MAX == (a6 | IPMask(IP6Addr::WIDTH))); + REQUIRE(IP6Addr::MIN == (a6 & IPMask(0))); + + IP6Addr a6_2{"2001:1f2d:c587:24c3:9128:3349:3cee:143"_tv}; + swoc::IPMask mask{127}; + CHECK(a6_2 == (a6_2 | mask)); + CHECK(a6_2 != (a6_2 & mask)); + CHECK(a6_2 == (a6_2 & swoc::IPMask(128))); // should always be a no-op. + + IP6Net n6_1{a6_2, IPMask(96)}; + CHECK(n6_1.min() == IP6Addr("2001:1f2d:c587:24c3:9128:3349::")); + + swoc::IP6Addr a6_3{"2001:1f2d:c587:24c4::"}; + CHECK(a6_3 == (a6_3 & swoc::IPMask{64})); + CHECK(a6_3 == (a6_3 & swoc::IPMask{62})); + CHECK(a6_3 != (a6_3 & swoc::IPMask{61})); + + REQUIRE(IPMask(1) == IPMask::mask_for(IP4Addr("0x80.0.0.0"))); + REQUIRE(IPMask(2) == IPMask::mask_for(IP4Addr("0xC0.0.0.0"))); + REQUIRE(IPMask(27) == IPMask::mask_for(IP4Addr("0xFF.0xFF.0xFF.0xE0"))); + REQUIRE(IPMask(55) == IPMask::mask_for(IP6Addr("1337:dead:beef:CA00::"))); + REQUIRE(IPMask(91) == IPMask::mask_for(IP6Addr("1337:dead:beef:CA00:24c3:3ce0::"))); } TEST_CASE("IP Formatting", "[libswoc][ip][bwformat]") { @@ -1121,15 +1124,14 @@ TEST_CASE("IPSpace docJJ", "[libswoc][ipspace][docJJ]") { unsigned idx; idx = 0; - for (auto spot = space.begin() ; spot != space.end() && idx < results.size() ; ++spot) { - auto const& [ range, bits ] { *spot }; - REQUIRE(idx < results.size()); + for (auto const& [range, bits] : space) { CHECK(bits == results[idx]); ++idx; } idx = 0; - for (auto const& [range, bits] : space) { + for (auto spot = space.begin() ; spot != space.end() && idx < results.size() ; ++spot ) { + auto const& [ range, bits ] { *spot }; CHECK(bits == results[idx]); ++idx; }
