This is an automated email from the ASF dual-hosted git repository.
amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 61b27c3403 Update to libswoc 1.5.0 (#9830)
61b27c3403 is described below
commit 61b27c340368e51e4879f82c1b7775b5000fd79e
Author: Alan M. Carroll <[email protected]>
AuthorDate: Thu Jun 15 08:59:01 2023 -0500
Update to libswoc 1.5.0 (#9830)
---
lib/swoc/CMakeLists.txt | 2 +-
lib/swoc/Makefile.am | 2 +-
lib/swoc/include/swoc/DiscreteRange.h | 234 ++++++++----
lib/swoc/include/swoc/IPRange.h | 700 ++++++++++++++++++++++++++--------
lib/swoc/include/swoc/Lexicon.h | 2 +-
lib/swoc/include/swoc/MemSpan.h | 23 +-
lib/swoc/include/swoc/bwf_base.h | 28 +-
lib/swoc/include/swoc/swoc_version.h | 6 +-
lib/swoc/src/swoc_file.cc | 2 +
lib/swoc/src/swoc_ip.cc | 96 +++--
proxy/ControlMatcher.cc | 2 +-
11 files changed, 798 insertions(+), 299 deletions(-)
diff --git a/lib/swoc/CMakeLists.txt b/lib/swoc/CMakeLists.txt
index 88a549ebe8..c49f8a67fc 100644
--- a/lib/swoc/CMakeLists.txt
+++ b/lib/swoc/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.11)
project(Lib-SWOC CXX)
-set(LIBSWOC_VERSION "1.4.10")
+set(LIBSWOC_VERSION "1.5.0")
set(CMAKE_CXX_STANDARD 17)
cmake_policy(SET CMP0087 NEW)
# override "lib64" to be "lib" unless the user explicitly sets it.
diff --git a/lib/swoc/Makefile.am b/lib/swoc/Makefile.am
index 98d72ca31d..d5d9b9261b 100644
--- a/lib/swoc/Makefile.am
+++ b/lib/swoc/Makefile.am
@@ -22,7 +22,7 @@ library_includedir=$(includedir)/swoc
AM_CPPFLAGS += @SWOC_INCLUDES@
-libtsswoc_la_LDFLAGS = @AM_LDFLAGS@ -no-undefined -release 1.4.10
+libtsswoc_la_LDFLAGS = @AM_LDFLAGS@ -no-undefined -release 1.5.0
libtsswoc_la_SOURCES = \
src/ArenaWriter.cc src/bw_format.cc src/bw_ip_format.cc
src/Errata.cc src/MemArena.cc src/RBTree.cc src/swoc_file.cc src/swoc_ip.cc
src/TextView.cc src/string_view_util.cc
diff --git a/lib/swoc/include/swoc/DiscreteRange.h
b/lib/swoc/include/swoc/DiscreteRange.h
index a04a3e7d27..ff681f2484 100644
--- a/lib/swoc/include/swoc/DiscreteRange.h
+++ b/lib/swoc/include/swoc/DiscreteRange.h
@@ -127,7 +127,7 @@ enum class DiscreteRangeEdgeRelation : uint8_t {
- have value semantics
- have minimum and maximum values either
- members @c MIN and @c MAX that define static instances
- - support @c std::numeric_limits<T>
+ - @c std::numeric_limits<T> support.
The interval is always an inclusive (closed) contiguous interval,
defined by the minimum and maximum values contained in the interval.
@@ -147,7 +147,7 @@ public:
using EdgeRelation = DiscreteRangeEdgeRelation; ///< Import type for
convenience.
/** Default constructor.
- An invalid (empty) range is constructed.
+ * An invalid (empty) range is constructed.
*/
constexpr DiscreteRange() : _min(detail::maximum<T>()),
_max(detail::minimum<T>()) {}
@@ -174,109 +174,139 @@ public:
*/
bool empty() const;
+ /** Update the range.
+ *
+ * @param min New minimum value.
+ * @param max New maximum value.
+ * @return @a this.
+ */
self_type &assign(metric_type const &min, metric_type const &max);
- /// Set the interval to be a singleton.
- self_type &assign(metric_type const &singleton);
+ /** Update the range.
+ *
+ * @param value The new minimum and maximum value.
+ * @return @a this.
+ *
+ * The range will contain the single value @a value.
+ */
+ self_type &assign(metric_type const &value);
+ /** Update the minimum value.
+ *
+ * @param min The new minimum value.
+ * @return @a this.
+ *
+ * @note No checks are done - this can result in an empty range.
+ */
self_type &assign_min(metric_type const &min);
+ /** Update the maximum value.
+ *
+ * @param max The new maximum value.
+ * @return @a this.
+ *
+ * @note No checks are done - this can result in an empty range.
+ */
self_type &assign_max(metric_type const &max);
/** Decrement the maximum value.
*
* @return @a this.
+ *
+ * @note No checks are done, the caller must ensure it is valid to
decremented the current maximum.
*/
- self_type &
- clip_max() {
- --_max;
- return *this;
- }
+ self_type & clip_max();
- /** Get the minimum value in the interval.
- @note The return value is unspecified if the interval is empty.
+ /** Minimum value.
+ * @return the minimum value in the range.
+ * @note The return value is unspecified if the interval is empty.
*/
metric_type const &min() const;
- /** Get the maximum value in the interval.
- @note The return value is unspecified if the interval is empty.
+ /** Maximum value.
+ * @return The maximum value in the range.
+ * @note The return value is unspecified if the interval is empty.
*/
metric_type const &max() const;
- /// Test for equality.
- bool
- operator==(self_type const &that) const {
- return _min == that._min && _max == that._max;
- }
+ /// Equality.
+ bool operator==(self_type const &that) const;
- /// Test for inequality.
- bool
- operator!=(self_type const &that) const {
- return _min != that._min | _max != that._max;
- }
+ /// Inequality.
+ bool operator!=(self_type const &that) const;
/** Check if a value is in @a this range.
*
- * @param m Metric value to check.
- * @return @c true if @a m is in the range, @c false if not.
+ * @param value Metric value to check.
+ * @return @c true if @a value is in the range, @c false if not.
*/
- bool
- contains(metric_type const &m) const {
- return _min <= m && m <= _max;
- }
+ bool contains(metric_type const &value) const;
- /** Logical intersection test for two intervals.
- @return @c true if there is at least one common value in the
- two intervals, @c false otherwise.
- */
+ /** Logical intersection.
+ * @return @c true if there is at least one common value in the two
intervals, @c false otherwise.
+ */
bool has_intersection_with(self_type const &that) const;
/** Compute the intersection of two intervals
- @return The interval consisting of values that are contained by
- both intervals. This may be the empty interval if the intervals
- are disjoint.
- @internal Co-variant
+ *
+ * @return The interval consisting of values that are contained by both
intervals. The return range
+ * is empty if the intervals are disjoint.
+ *
+ * @internal Co-variant
*/
self_type intersection(self_type const &that) const;
/** Test for adjacency.
- @return @c true if the intervals are adjacent.
- @note Only disjoint intervals can be adjacent.
+ * @return @c true if the intervals are adjacent.
+ * @note Only disjoint intervals can be adjacent.
*/
bool is_adjacent_to(self_type const &that) const;
- /** Test for @a this being adjacent on the left of @a that.
+ /** Lower adjacency.
*
* @param that Range to check for adjacency.
- * @return @c true if @a this ends exactly the value before @a that begins.
+ * @return @c true if @a this and @ta that are adjacent and @a this is less
than @a that.
*/
bool is_left_adjacent_to(self_type const &that) const;
- //! Test if the union of two intervals is also an interval.
+ /** Valid union.
+ *
+ * @param that Range to compare.
+ *
+ * @return @a true if the hull of @a this and @a that contains only elements
that are also in
+ * @a this or @a that.
+ */
bool has_union(self_type const &that) const;
- /** Test if an interval is a superset of or equal to another.
- @return @c true if every value in @c that is also in @c this.
+ /** Superset test.
+ *
+ * @return @c true if every value in @c that is also in @c this.
*/
bool is_superset_of(self_type const &that) const;
- /** Test if an interval is a subset or equal to another.
- @return @c true if every value in @c this is also in @c that.
+ /** Subset test.
+ *
+ * @return @c true if every value in @c this is also in @c that.
*/
bool is_subset_of(self_type const &that) const;
- /** Test if an interval is a strict superset of another.
- @return @c true if @c this is strictly a superset of @a rhs.
+ /** Strict superset test.
+ *
+ * @return @c true if @a this contains every value in @a this and @a this
has at least one value not
+ * in @a that.
*/
bool is_strict_superset_of(self_type const &that) const;
- /** Test if an interval is a strict subset of another.
- @return @c true if @c this is strictly a subset of @a that.
+ /** Strict subset test.
+ *
+ * @return @c true if @a that contains every value in @a this and @a that
has at least one value not
+ * in @a this.
*/
bool is_strict_subset_of(self_type const &that) const;
- /** Determine the relationship between @c this and @a that interval.
- @return The relationship type.
+ /** Generic relationship.
+ *
+ * @return The relationship between @a this and @a that.
*/
Relation relationship(self_type const &that) const;
@@ -292,18 +322,11 @@ public:
* - OVLP: @a that left edge is inside @a this.
* - NONE: @a that left edge is left of @a this.
*/
- EdgeRelation
- left_edge_relationship(self_type const &that) const {
- if (_max < that._max) {
- return ++metric_type(_max) < that._max ? EdgeRelation::GAP :
EdgeRelation::ADJ;
- }
- return _min >= that._min ? EdgeRelation::NONE : EdgeRelation::OVLP;
- }
+ EdgeRelation left_edge_relationship(self_type const &that) const;
- /** Compute the convex hull of this interval and another one.
- @return The smallest interval that is a superset of @c this
- and @a that interval.
- @internal Co-variant
+ /** Convex hull.
+ * @return The smallest interval that is a superset of @c this and @a that.
+ * @internal Co-variant
*/
self_type hull(self_type const &that) const;
@@ -313,36 +336,32 @@ public:
/** Test for empty, operator form.
@return @c true if the interval is empty, @c false otherwise.
*/
- bool
- operator!() const {
- return _min > _max;
- }
+ bool operator!() const;
/** Test for non-empty.
*
* @return @c true if there values in the range, @c false if no values in
the range.
*/
- explicit operator bool() const { return _min <= _max; }
+ explicit operator bool() const;
- /// @return @c true if the range is maximal, @c false otherwise.
+ /** Maximality.
+ * @return @c true if this range contains every value.
+ */
bool is_maximal() const;
/** Clip interval.
- Remove all element in @c this interval not in @a that interval.
+ * Remove all element in @c this interval not in @a that interval.
*/
self_type &operator&=(self_type const &that);
/** Convex hull.
- Extend interval to cover all elements in @c this and @a that.
+ * Minimally extend @a this to cover all elements in @c this and @a that.
+ * @return @a this.
*/
self_type &operator|=(self_type const &that);
- self_type &
- clear() {
- _min = detail::maximum<T>();
- _max = detail::minimum<T>();
- return *this;
- }
+ /// Make the range empty.
+ self_type & clear();
/** Functor for lexicographic ordering.
If, for some reason, an interval needs to be put in a container
@@ -368,6 +387,47 @@ public:
};
};
+template <typename T>
+bool
+DiscreteRange<T>::operator==(DiscreteRange::self_type const &that) const {
+ return _min == that._min && _max == that._max;
+}
+
+template <typename T>
+bool
+DiscreteRange<T>::operator!=(DiscreteRange::self_type const &that) const {
+ return _min != that._min | _max != that._max;
+}
+
+template <typename T>
+auto
+DiscreteRange<T>::clip_max() -> self_type & {
+ --_max;
+ return *this;
+}
+
+template <typename T>
+bool
+DiscreteRange<T>::operator!() const {
+ return _min > _max;
+}
+
+template <typename T> DiscreteRange<T>::operator bool() const { return _min <=
_max; }
+
+template <typename T>
+bool
+DiscreteRange<T>::contains(metric_type const &value) const {
+ return _min <= value && value <= _max;
+}
+
+template <typename T>
+auto
+DiscreteRange<T>::clear() -> self_type & {
+ _min = detail::maximum<T>();
+ _max = detail::minimum<T>();
+ return *this;
+}
+
template <typename T>
bool
DiscreteRange<T>::lexicographic_order::operator()(DiscreteRange::self_type
const &lhs, DiscreteRange::self_type const &rhs) const {
@@ -390,8 +450,17 @@ DiscreteRange<T>::hull(DiscreteRange::self_type const
&that) const {
}
template <typename T>
-typename DiscreteRange<T>::Relation
-DiscreteRange<T>::relationship(self_type const &that) const {
+auto
+DiscreteRange<T>::left_edge_relationship(self_type const &that) const ->
EdgeRelation {
+ if (_max < that._max) {
+ return ++metric_type(_max) < that._max ? EdgeRelation::GAP :
EdgeRelation::ADJ;
+ }
+ return _min >= that._min ? EdgeRelation::NONE : EdgeRelation::OVLP;
+}
+
+template <typename T>
+auto
+DiscreteRange<T>::relationship(self_type const &that) const -> Relation{
Relation retval = Relation::NONE;
if (this->has_intersection(that)) {
if (*this == that)
@@ -534,7 +603,8 @@
DiscreteRange<T>::is_left_adjacent_to(DiscreteRange::self_type const &that) cons
* T has a modulus and not depend on ++t > t always being true. However, we
know that if t1 >
* t0 then ++t0 > t0.
*/
- return _max < that._min && ++metric_type(_max) == that._min;
+ metric_type max(_max); // some built in integer types don't support
increment on rvalues.
+ return _max < that._min && ++max == that._min;
}
template <typename T>
@@ -543,10 +613,6 @@ DiscreteRange<T>::intersection(DiscreteRange::self_type
const &that) const {
return {std::max(_min, that._min), std::min(_max, that._max)};
}
-/** Equality.
- Two intervals are equal if their min and max values are equal.
- @relates DiscreteRange
- */
template <typename T>
bool
operator==(DiscreteRange<T> const &lhs, DiscreteRange<T> const &rhs) {
diff --git a/lib/swoc/include/swoc/IPRange.h b/lib/swoc/include/swoc/IPRange.h
index aa93d17e65..b6e68f5ce3 100644
--- a/lib/swoc/include/swoc/IPRange.h
+++ b/lib/swoc/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> {
@@ -33,7 +30,7 @@ class IP4Range : public DiscreteRange<IP4Addr> {
public:
/// Default constructor, invalid range.
- IP4Range() = default;
+ constexpr IP4Range() = default;
/// Construct from an network expressed as @a addr and @a mask.
IP4Range(IP4Addr const &addr, IPMask const &mask);
@@ -47,8 +44,10 @@ public:
* @param text Range text.
* @see IP4Range::load
*
- * This results in a zero address if @a text is not a valid string. If this
should be checked,
+ * This results in an empty range if @a text is not a valid string. If this
should be checked,
* use @c load.
+ *
+ * @see load
*/
IP4Range(string_view const &text);
@@ -186,9 +185,9 @@ public:
/** Construct range from @a text.
*
* @param text Range text.
- * @see IP4Range::load
+ * @see IP6Range::load
*
- * This results in a zero address if @a text is not a valid string. If this
should be checked,
+ * This results in an empty range if @a text is not a valid string. If this
should be checked,
* use @c load.
*/
IP6Range(string_view const &text);
@@ -311,6 +310,8 @@ protected:
bool is_valid(IPMask const &mask);
};
+class IPRangeView; // Forward declare.
+
/** Range of IP addresses.
* Although this can hold IPv4 or IPv6, any specific instance is one or the
other, this can never contain
* a range of different address families.
@@ -335,6 +336,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 +348,8 @@ public:
*
* @param addr Address of range.
*/
-
IPRange(IPAddr const& addr) : IPRange(addr, addr) {}
+
/** Construct a singleton range.
*
* @param addr Address of range.
@@ -366,6 +368,8 @@ public:
/// Construct from an IPv6 @a range.
IPRange(IP6Range const &range);
+ /// Construct from view.
+ IPRange(IPRangeView const& view);
/** Construct from a string format.
*
@@ -375,25 +379,35 @@ public:
*/
IPRange(string_view const &text);
+ /** Update with an IPv4 range.
+ *
+ * @param min Minimum value.
+ * @param max Maximum value.
+ * @return @a this.
+ */
self_type & assign(IP4Addr const& min, IP4Addr const& max);
+
+ /** Update with an IPv6 range.
+ *
+ * @param min Minimum address.
+ * @param max Maximum address.
+ * @return @a this
+ */
self_type & assign(IP6Addr const& min, IP6Addr const& max);
+ /// Assign from view.
+ self_type & operator = (IPRangeView const& rv);
+
/// Equality
bool operator==(self_type const &that) const;
/// Inequality
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 +435,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 +455,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 +491,7 @@ protected:
IP4Range _ip4; ///< IPv4 range.
IP6Range _ip6; ///< IPv6 range.
} _range{std::monostate{}};
+
/// Family of @a _range.
sa_family_t _family{AF_UNSPEC};
};
@@ -490,6 +509,9 @@ public:
/// Construct from @a range.
explicit NetSource(range_type const &range);
+ /// Construct from view.
+ explicit NetSource(IPRangeView const& rv);
+
/// Copy constructor.
NetSource(self_type const &that) = default;
@@ -533,9 +555,98 @@ protected:
IP4Range::NetSource _ip4; ///< IPv4 addresses.
IP6Range::NetSource _ip6; ///< IPv6 addresses.
};
+
sa_family_t _family = AF_UNSPEC; ///< Mark for union content.
};
+/** View of a range.
+ *
+ * The point of this is @c IPRange is really a union on top of @c IP4Range and
@c IP6Range therefore
+ * using it requires copying. A view enable using an IPv4 or IPv6 range as a
generic range without
+ * the copy. This is useful in situations where performance is critical.
+ *
+ * Used primarily for iterator implementation where the ranges are stored in
family specific ranges
+ * in the container. The iterator can use this to provide access as an @c
IPRange without a copying
+ * every iteration.
+ *
+ * @note An earlier implementation used references and updated those to
achieve this same effect but
+ * that appeared to confusion the optimizer and odd effects would happen at
higher optimization levels
+ * (in particular, iterators would appear to not actually increment even
thought the increment code
+ * was invoked).
+ */
+class IPRangeView {
+ using self_type = IPRangeView;
+ friend IPRange;
+ /// Storage for the view pointer - union because only one can be valid.
+ using storage_type = union {
+ std::monostate _nil; ///< No data present.
+ IP4Range const * _4; ///< IPv4 range.
+ IP6Range const * _6; ///< IPv6 range.
+ };
+public:
+ /// Default constructor - invalid view.
+ IPRangeView() = default;
+
+ /// Compare to a range.
+ bool operator == (IPRange const& r) const;
+
+ /// @return @c true if there is no valid view to a range.
+ bool valid() const;
+
+ // @return @c true if the range is empty (invalid views are empty)
+ bool empty() const;
+
+ /// Reset to invalid view.
+ self_type & clear();
+
+ /// Update the view.
+ self_type & assign(IP4Range const& r);
+
+ /// Update the view.
+ self_type & assign(IP6Range const& r);
+
+ /// @return @c true if this is an IPv4 range.
+ bool is_ip4() const;
+
+ /// @return @c true if this is an IPv6 range.
+ bool is_ip6() const;
+
+ /// @return Reference to the viewed IPv4 range.
+ IP4Range const& ip4() const;
+
+ /// @return Reference to the viewd IPv6 range.
+ IP6Range const& ip6() const;
+
+ /// @{
+ /// Forwarding methods.
+
+ /// @return The minimum address in the range.
+ IPAddr min() const;
+
+ /// @return The maximum value in the range.
+ IPAddr max() const;
+
+ /// Equality.
+ bool operator == (self_type const& that) const;
+
+ /// Inequality.
+ bool operator != (self_type const& that) const;
+
+ /** Generate a list of networks covering @a this range.
+ *
+ * @return A network generator.
+ *
+ * @see IPRange::networks
+ */
+ IPRange::NetSource networks() const { return IPRange::NetSource(*this); }
+
+ /// @}
+
+// protected:
+ storage_type _raw = { std::monostate() }; ///< Storage for the view pointer.
+ sa_family_t _family = AF_UNSPEC; ///< Range address family.
+};
+
/// An IPv4 network.
class IP4Net {
using self_type = IP4Net; ///< Self reference type.
@@ -563,8 +674,8 @@ public:
*/
bool load(swoc::TextView text);
- /// @return @c true if the network is valid, @c false if not.
- bool is_valid() const;
+ /// @return @c true if the network contains no addresses (is invalid).
+ bool empty() const;
/// @return Network address - smallest address in the network.
IP4Addr min() const;
@@ -572,12 +683,6 @@ public:
/// @return The largest address in the network.
IP4Addr max() const;
- /// @return Network address.
- [[deprecated]] IP4Addr lower_bound() const;
-
- /// @return The largest address in the network.
- [[deprecated]] IP4Addr upper_bound() const;
-
/// @return The mask for the network.
IPMask const &mask() const;
@@ -624,6 +729,15 @@ public:
*/
IP6Net(IP6Addr addr, IPMask mask);
+ /** Construct from text.
+ *
+ * @param text Network description.
+ *
+ * The format must be "addr/mask" where "addr" is a valid address and mask
is either a single
+ * number for the mask width (CIDR) or a mask in address notation.
+ */
+ IP6Net(TextView text) { this->load(text); }
+
/** Parse network as @a text.
*
* @param text String describing the network in CIDR format.
@@ -631,8 +745,8 @@ public:
*/
bool load(swoc::TextView text);
- /// @return @c true if the network is valid, @c false if not.
- bool is_valid() const;
+ /// @return @c true if the network contains no addresses (is invalid).
+ bool empty() const;
/// @return Network address - smallest address in the network.
IP6Addr min() const;
@@ -640,12 +754,6 @@ public:
/// @return Largest address in the network.
IP6Addr max() const;
- /// @return THh smallest address in the network.
- [[deprecated]] IP6Addr lower_bound() const;
-
- /// @return The largest address in the network.
- [[deprecated]] IP6Addr upper_bound() const;
-
/// @return The mask for the network.
IPMask const &mask() const;
@@ -698,6 +806,13 @@ public:
*/
IPNet(IPAddr const &addr, IPMask const &mask);
+ /** Construct from text.
+ *
+ * @param text Network description.
+ *
+ * The format must be "addr/mask" where "addr" is a valid address and mask
is either a single
+ * number for the mask width (CIDR) or a mask in address notation.
+ */
IPNet(TextView text);
/** Parse network as @a text.
@@ -707,8 +822,8 @@ public:
*/
bool load(swoc::TextView text);
- /// @return @c true if the network is valid, @c false if not.
- bool is_valid() const;
+ /// @return @c true if the network contains no addresses (is invalid).
+ bool empty() const;
/// @return Network address - smallest address in the network.
IPAddr min() const;
@@ -716,12 +831,7 @@ public:
/// @return Largest address in the network.
IPAddr max() const;
- /// @return THh smallest address in the network.
- [[deprecated]] IPAddr lower_bound() const;
-
- /// @return The largest address in the network.
- [[deprecated]] IPAddr upper_bound() const;
-
+ /// @return The number of bits in the mask.
IPMask::raw_type width() const;
/// @return The mask for the network.
@@ -730,21 +840,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 +864,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 +878,135 @@ protected:
};
// --------------------------------------------------------------------------
+namespace detail {
+/** Value type for @c IPSpace constant iterator.
+ *
+ * @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.
+ *
+ * @internal The value type must be split in two to provide @c const
consistency. The structured
+ * bidingin types are determined only by the type of the value, therefore if
the structured binding
+ * should vary in whether the payload binding is @c const then there must be
two types. I tested using
+ * @c const in the typle type templates but the binding always used the @c
const variant regardless of
+ * the @const state of the payload instance.
+ *
+ * @note The @c assign methods are used to update iterators.
+ *
+ * @see IPSpace
+ */
+template < typename PAYLOAD > struct ip_space_const_value_type {
+ using self_type = ip_space_const_value_type;
+
+ IPRangeView _rv; ///< View to the current range.
+ PAYLOAD * _payload = nullptr; ///< Payload for @a _range.
+
+ ip_space_const_value_type() = default;
+
+ /// Reset to default constructed state.
+ self_type & clear();
+
+ /** Update the internal state.
+ *
+ * @param r Range.
+ * @param payload Payload.
+ * @return @a this.
+ */
+ self_type & assign(IP4Range const& r, PAYLOAD & payload);
+
+ /** Update the internal state.
+ *
+ * @param r Range.
+ * @param payload Payload.
+ * @return @a this.
+ */
+ self_type & assign(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.
+ std::tuple<IPRangeView, PAYLOAD &> tuple() const { return { _rv, *_payload
}; }
+
+ /// Equality against an equivalent tuple.
+ bool operator == (std::tuple<swoc::IPRange, PAYLOAD> const& t) const;
+
+ /// @return The address range.
+ IPRange range() const { return _rv; }
+
+ /// @return The range view.
+ IPRangeView range_view() const { return _rv; }
+
+ /// @return A reference to the payload (user content).
+ PAYLOAD const & payload() const { return *_payload; }
+};
+
+/** 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 :
ip_space_const_value_type<PAYLOAD> {
+ using self_type = ip_space_value_type;
+ using super_type = ip_space_const_value_type<PAYLOAD>;
+
+ /// @return A reference to the payload (user content).
+ PAYLOAD & payload() { return *super_type::_payload; }
+
+};
+
+template <typename PAYLOAD>
+auto
+ip_space_const_value_type<PAYLOAD>::clear() -> self_type & {
+ _rv.clear();
+ _payload = nullptr;
+ return *this;
+}
+
+template <typename PAYLOAD>
+auto
+ip_space_const_value_type<PAYLOAD>::assign(IP4Range const &r, PAYLOAD
&payload) -> self_type &{
+ _rv.assign(r);
+ _payload = &payload;
+ return *this;
+}
+
+template <typename PAYLOAD>
+auto
+ip_space_const_value_type<PAYLOAD>::assign(IP6Range const &r, PAYLOAD
&payload) -> self_type & {
+ _rv.assign(r);
+ _payload = &payload;
+ return *this;
+}
+
+template <typename PAYLOAD>
+auto
+ip_space_const_value_type<PAYLOAD>::assign(ip_space_const_value_type::self_type
const &that) -> self_type & {
+ _rv = that._rv;
+ _payload = that._payload;
+ return *this;
+}
+
+template <typename PAYLOAD>
+bool
+ip_space_const_value_type<PAYLOAD>::operator==(std::tuple<swoc::IPRange,
PAYLOAD> const &t) const {
+ return _rv == std::get<0>(t) && std::get<1>(t) == *_payload;
+}
+
+} // namespace detail
+
/** Coloring of IP address space.
*
* @tparam PAYLOAD The color class.
@@ -793,7 +1027,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 +1085,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,11 +1132,11 @@ public:
friend class IPSpace;
public:
- using value_type = std::tuple<IPRange const, PAYLOAD const &>; /// Import
for API compliance.
+ using value_type = detail::ip_space_const_value_type<PAYLOAD>; /// Import
for API compliance.
// STL algorithm compliance.
using iterator_category = std::bidirectional_iterator_tag;
- using pointer = value_type *;
- using reference = value_type &;
+ using pointer = value_type const *;
+ using reference = value_type const &;
using difference_type = int;
/// Default constructor.
@@ -936,31 +1170,11 @@ public:
/// 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;
-
- /** 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;
+ pointer operator->() const;
/// Equality
bool operator==(self_type const &that) const;
@@ -977,7 +1191,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)};
+ value_type _value;
/** Internal constructor.
*
@@ -987,6 +1201,14 @@ public:
* In practice, at most one iterator should be "internal", the other
should be the beginning or end.
*/
const_iterator(typename IP4Space::iterator const &iter4, typename
IP6Space::iterator const &iter6);
+
+ // These are required because the actual range type is @c
DiescreteRange<T> and returning as a
+ // range class creates a temporary which in turns causes some nasty side
effects.
+
+ /// @return Properly type cast range from iterator.
+ IP4Range const& r4() { return static_cast<IP4Range
const&>(_iter_4->range()); }
+ /// @return Properly type cast range from iterator.
+ IP6Range const& r6() { return static_cast<IP6Range
const&>(_iter_6->range()); }
};
/** Iterator.
@@ -1008,7 +1230,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 = detail::ip_space_value_type<PAYLOAD>;
using pointer = value_type *;
using reference = value_type &;
@@ -1034,31 +1256,24 @@ 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;
+ protected:
+ // Retrieve the value and convert from the super (const) type value to the
value for iterator.
+ value_type & value() const;
};
/** Find the payload for an @a addr.
@@ -1254,12 +1469,11 @@ public:
friend class IPRangeSet;
public:
- using value_type = IPRange const;
+ using value_type = IPRangeView;
// STL algorithm compliance.
using iterator_category = std::bidirectional_iterator_tag;
- using pointer = value_type *;
- using reference = value_type &;
- using const_reference = value_type const &;
+ using pointer = value_type const *;
+ using reference = value_type const &;
using difference_type = int;
/// Default constructor.
@@ -1293,11 +1507,11 @@ public:
/// Dereference.
/// @return A reference to the referent.
- value_type const& operator*() const;
+ reference operator*() const;
/// Dereference.
/// @return A pointer to the referent.
- value_type const *operator->() const;
+ pointer operator->() const;
/// Equality
bool operator==(self_type const &that) const;
@@ -1309,6 +1523,7 @@ public:
const_iterator(super_type const& spot) : _iter(spot) {}
super_type _iter; ///< Underlying iterator.
+ IPRange _r; ///< Some less temporary storage for dereferences.
};
using iterator = const_iterator;
@@ -1376,9 +1591,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(this->r4(), _iter_4->payload());
} else if (_iter_6.has_next()) {
- new (&_value) value_type{_iter_6->range(), _iter_6->payload()};
+ _value.assign(this->r6(), _iter_6->payload());
}
}
@@ -1387,7 +1602,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 +1614,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(this->r4(), _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(this->r6(), _iter_6->payload());
return *this;
}
}
- new (&_value) value_type{IPRange{}, *static_cast<PAYLOAD
*>(detail::pseudo_nullptr)};
+ _value.clear();
return *this;
}
@@ -1427,15 +1642,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(this->r6(), _iter_6->payload());
return *this;
}
if (_iter_4.has_prev()) {
--_iter_4;
- new (&_value) value_type{_iter_4->range(), _iter_4->payload()};
+ _value.assign(this->r4(), _iter_4->payload());
return *this;
}
- new (&_value) value_type{IPRange{}, *static_cast<PAYLOAD
*>(detail::pseudo_nullptr)};
+ _value.clear();
return *this;
}
@@ -1449,24 +1664,16 @@ 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 -> reference {
return _value;
}
template <typename PAYLOAD>
auto
-IPSpace<PAYLOAD>::const_iterator::operator->() const -> value_type const * {
+IPSpace<PAYLOAD>::const_iterator::operator->() const -> pointer {
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 +1703,20 @@ 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::value() const -> value_type & {
+ return reinterpret_cast<value_type&>(const_cast<self_type*>(this)->_value);
+}
+
+template <typename PAYLOAD>
+auto
+IPSpace<PAYLOAD>::iterator::operator->() const -> pointer {
+ return &(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 this->value();
}
template <typename PAYLOAD>
@@ -1513,6 +1726,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 +1741,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 +++
@@ -1563,6 +1791,14 @@ inline IPRange::IPRange(string_view const &text) {
this->load(text);
}
+inline IPRange::IPRange(IPRangeView const& view) {
+ if (AF_INET == view._family) {
+ *this = *view._raw._4;
+ } else if (AF_INET6 == _family) {
+ *this = *view._raw._6;
+ }
+}
+
inline auto
IPRange::assign(IP4Addr const &min, IP4Addr const &max) -> self_type & {
_range._ip4.assign(min, max);
@@ -1577,6 +1813,22 @@ IPRange::assign(IP6Addr const &min, IP6Addr const &max)
-> self_type & {
return *this;
}
+inline auto
+IPRange::operator=(const IPRangeView &rv) -> self_type & {
+ if (AF_INET == rv._family) {
+ *this = *rv._raw._4;
+ } else if (AF_INET6 == rv._family) {
+ *this = *rv._raw._6;
+ }
+ return *this;
+}
+
+inline auto
+IPRange::clear() -> self_type & {
+ _family = AF_UNSPEC;
+ return *this;
+}
+
inline auto
IPRange::networks() const -> NetSource {
return {NetSource{*this}};
@@ -1592,6 +1844,68 @@ 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;
+}
+
+inline auto
+IPRangeView::clear() -> self_type & {
+ _family = AF_UNSPEC;
+ return *this;
+}
+
+inline bool
+IPRangeView::empty() const {
+ return AF_INET6 == _family ? _raw._6->empty()
+ : AF_INET == _family ? _raw._4->empty()
+ : true;
+}
+
+inline bool IPRangeView::is_ip4() const { return AF_INET == _family; }
+
+inline bool IPRangeView::is_ip6() const { return AF_INET6 == _family; }
+
+inline IP4Range const & IPRangeView::ip4() const { return *_raw._4; }
+
+inline IP6Range const & IPRangeView::ip6() const { return *_raw._6; }
+
+inline bool
+IPRangeView::valid() const { return AF_INET == _family || AF_INET6 == _family;
}
+
+inline auto
+IPRangeView::assign(IP4Range const &r) -> self_type & {
+ _family = r.family();
+ _raw._4 = &r;
+ return *this;
+}
+
+inline auto
+IPRangeView::assign(IP6Range const &r) -> self_type & {
+ _family = r.family();
+ _raw._6 = &r;
+ return *this;
+}
+
+inline bool
+IPRangeView::operator!=(IPRangeView::self_type const &that) const {
+ return ! (*this == that);
+}
+
+inline IPAddr
+IPRangeView::min() const {
+ return AF_INET == _family ? _raw._4->min() : AF_INET6 == _family ?
_raw._6->min() : IPAddr::INVALID;
+}
+
+inline IPAddr
+IPRangeView::max() const {
+ return AF_INET == _family ? _raw._4->max() : AF_INET6 == _family ?
_raw._6->max() : IPAddr::INVALID;
+}
+
// +++ IPNet +++
inline IP4Net::IP4Net(swoc::IP4Addr addr, swoc::IPMask mask) : _addr(addr &
mask), _mask(mask) {}
@@ -1602,8 +1916,8 @@ IP4Net::mask() const {
}
inline bool
-IP4Net::is_valid() const {
- return _mask.is_valid();
+IP4Net::empty() const {
+ return ! _mask.is_valid();
}
inline IP4Addr
@@ -1616,16 +1930,6 @@ IP4Net::max() const {
return _addr | _mask;
}
-inline IP4Addr
-IP4Net::lower_bound() const {
- return this->min();
-}
-
-inline IP4Addr
-IP4Net::upper_bound() const {
- return this->max();
-}
-
inline IP4Range
IP4Net::as_range() const {
return {this->min(), this->max()};
@@ -1656,8 +1960,8 @@ IP6Net::mask() const {
}
inline bool
-IP6Net::is_valid() const {
- return _mask.is_valid();
+IP6Net::empty() const {
+ return ! _mask.is_valid();
}
inline IP6Addr
@@ -1670,9 +1974,6 @@ IP6Net::max() const {
return _addr | _mask;
}
-inline IP6Addr IP6Net::lower_bound() const { return this->min(); }
-inline IP6Addr IP6Net::upper_bound() const { return this->max(); }
-
inline IP6Range
IP6Net::as_range() const {
return {this->min(), this->max()};
@@ -1702,8 +2003,8 @@ inline IPNet::IPNet(TextView text) {
}
inline bool
-IPNet::is_valid() const {
- return _mask.is_valid();
+IPNet::empty() const {
+ return ! _mask.is_valid();
}
inline IPAddr
@@ -1716,9 +2017,6 @@ IPNet::max() const {
return _addr | _mask;
}
-inline IPAddr IPNet::lower_bound() const { return this->min(); }
-inline IPAddr IPNet::upper_bound() const { return this->max(); }
-
inline IPMask::raw_type
IPNet::width() const {
return _mask.width();
@@ -1771,6 +2069,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
@@ -1883,6 +2197,16 @@ inline
IPRange::NetSource::NetSource(IPRange::NetSource::range_type const &range
}
}
+inline IPRange::NetSource::NetSource(IPRangeView const &rv) {
+ if (rv.is_ip4()) {
+ new (&_ip4) decltype(_ip4)(rv.ip4());
+ _family = AF_INET;
+ } else if (rv.is_ip6()) {
+ new (&_ip6) decltype(_ip6)(rv.ip6());
+ _family = AF_INET6;
+ }
+}
+
inline auto
IPRange::NetSource::begin() const -> iterator {
return *this;
@@ -2179,13 +2503,13 @@ IPRangeSet::const_iterator::operator--(int) ->
self_type {
}
inline auto
-IPRangeSet::const_iterator::operator*() const -> value_type const& {
- return _iter.range();
+IPRangeSet::const_iterator::operator*() const -> reference {
+ return _iter->_rv;
}
inline auto
-IPRangeSet::const_iterator::operator->() const -> value_type const * {
- return &(_iter.range());
+IPRangeSet::const_iterator::operator->() const -> pointer {
+ return &(_iter->_rv);
}
inline bool
@@ -2284,3 +2608,69 @@ 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 <typename P> class
tuple_size<swoc::detail::ip_space_const_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 <size_t IDX, typename P> class tuple_element<IDX,
swoc::detail::ip_space_const_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::IPRangeView;
+};
+
+template <typename P> class tuple_element<1,
swoc::detail::ip_space_value_type<P>> {
+public:
+ using type = P &;
+};
+
+template <typename P> class tuple_element<0,
swoc::detail::ip_space_const_value_type<P>> {
+public:
+ using type = swoc::IPRangeView;
+};
+
+template <typename P> class tuple_element<1,
swoc::detail::ip_space_const_value_type<P>> {
+public:
+ using type = P const &;
+};
+
+} // namespace std
+
+namespace swoc { inline namespace SWOC_VERSION_NS { namespace detail {
+template <size_t IDX, typename P>
+auto
+get(ip_space_const_value_type<P> const& p) -> typename std::tuple_element<IDX,
ip_space_const_value_type<P>>::type {
+ if constexpr (IDX == 0) {
+ return p._rv;
+ } else if constexpr (IDX == 1) {
+ return *(p._payload);
+ }
+}
+
+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._rv;
+ } else if constexpr (IDX == 1) {
+ return *(p._payload);
+ }
+}
+}}} // 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/lib/swoc/include/swoc/Lexicon.h b/lib/swoc/include/swoc/Lexicon.h
index c81337f633..166cb6f21a 100644
--- a/lib/swoc/include/swoc/Lexicon.h
+++ b/lib/swoc/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/lib/swoc/include/swoc/MemSpan.h b/lib/swoc/include/swoc/MemSpan.h
index 8b71e0cc02..d586493fe0 100644
--- a/lib/swoc/include/swoc/MemSpan.h
+++ b/lib/swoc/include/swoc/MemSpan.h
@@ -354,12 +354,6 @@ public:
/// Destruct all elements in the span.
void destroy();
- /** Return a view of the memory.
- *
- * @return A @c string_view covering the span contents.
- */
- [[deprecated]] std::string_view view() const;
-
template <typename U> friend class MemSpan;
};
@@ -616,12 +610,6 @@ public:
*/
self_type align(size_t alignment, size_t obj_size) const;
- /** Return a view of the memory.
- *
- * @return A @c string_view covering the span contents.
- */
- [[deprecated]] std::string_view view() const;
-
};
template <> class MemSpan<void> : public MemSpan<void const> {
@@ -1231,11 +1219,6 @@ MemSpan<T>::destroy() {
}
}
-template <typename T>
-std::string_view
-MemSpan<T>::view() const {
- return {reinterpret_cast<const char *>(_ptr), this->data_size()};
-}
// --- void specializations ---
template <typename U> constexpr MemSpan<void const>::MemSpan(MemSpan<U> const
&that) : _ptr(const_cast<std::remove_const_t<U> *>(that._ptr)), _size(sizeof(U)
* that.size()) {}
@@ -1533,13 +1516,11 @@ MemSpan<void const>::as_ptr() const {
return static_cast<U const *>(_ptr);
}
-inline std::string_view
-MemSpan<void const>::view() const {
- return {static_cast<char const *>(_ptr), _size};
-}
/// Deduction guides
template<typename T, size_t N> MemSpan(std::array<T,N> &) -> MemSpan<T>;
template<typename T, size_t N> MemSpan(std::array<T,N> const &) -> MemSpan<T
const>;
+template<size_t N> MemSpan(char (&)[N]) -> MemSpan<char>;
+template<size_t N> MemSpan(char const (&)[N]) -> MemSpan<char const>;
template<typename T> MemSpan(std::vector<T> &) -> MemSpan<T>;
template<typename T> MemSpan(std::vector<T> const&) -> MemSpan<T const>;
MemSpan(std::string_view const&) -> MemSpan<char const>;
diff --git a/lib/swoc/include/swoc/bwf_base.h b/lib/swoc/include/swoc/bwf_base.h
index f2e69c7bb2..39e998a2fc 100644
--- a/lib/swoc/include/swoc/bwf_base.h
+++ b/lib/swoc/include/swoc/bwf_base.h
@@ -134,6 +134,9 @@ protected:
struct Format {
using self_type = Format; ///< Self reference type.
+ /// Empty format.
+ Format() = default;
+
/// Construct from a format string @a fmt.
Format(TextView fmt);
@@ -196,11 +199,16 @@ struct Format {
/// @return @c true if all specifiers are literal.
bool is_literal() const;
-protected:
- /// Default constructor for use by subclasses with alternate formatting.
- Format() = default;
+ using Container = std::vector<Spec>;
+ Container _items; ///< Items from format string.
- std::vector<Spec> _items; ///< Items from format string.
+ using iterator = Container::iterator;
+ using const_iterator = Container::const_iterator;
+
+ iterator begin() { return _items.begin(); }
+ iterator end() { return _items.end(); }
+ const_iterator begin() const { return _items.begin(); }
+ const_iterator end() const { return _items.end(); }
};
// Name binding - support for having format specifier names.
@@ -271,11 +279,14 @@ public:
* suitable for the subclass generators.
*/
template <typename F> class NameMap {
-private:
- using self_type = NameMap; ///< self reference type.
public:
/// Signature for generators.
using Generator = std::function<F>;
+protected:
+ using Map = std::unordered_map<std::string_view, Generator>;
+private:
+ using self_type = NameMap; ///< self reference type.
+public:
/// Construct an empty container.
NameMap();
@@ -290,12 +301,15 @@ public:
*/
self_type &assign(std::string_view const &name, Generator const &generator);
+ bool contains(std::string_view name) {
+ return _map.end() != _map.find(name);
+ }
+
protected:
/// Copy @a name in to local storage and return a view of it.
std::string_view localize(std::string_view const &name);
/// Name to name generator.
- using Map = std::unordered_map<std::string_view, Generator>;
Map _map; ///< Defined generators.
MemArena _arena{1024}; ///< Local name storage.
};
diff --git a/lib/swoc/include/swoc/swoc_version.h
b/lib/swoc/include/swoc/swoc_version.h
index 137945b003..91543d678c 100644
--- a/lib/swoc/include/swoc/swoc_version.h
+++ b/lib/swoc/include/swoc/swoc_version.h
@@ -23,11 +23,11 @@
#pragma once
#if !defined(SWOC_VERSION_NS)
-#define SWOC_VERSION_NS _1_4_10
+#define SWOC_VERSION_NS _1_5_0
#endif
namespace swoc { inline namespace SWOC_VERSION_NS {
static constexpr unsigned MAJOR_VERSION = 1;
-static constexpr unsigned MINOR_VERSION = 4;
-static constexpr unsigned POINT_VERSION = 10;
+static constexpr unsigned MINOR_VERSION = 5;
+static constexpr unsigned POINT_VERSION = 0;
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/lib/swoc/src/swoc_file.cc b/lib/swoc/src/swoc_file.cc
index bfb34b0298..44ea3e7426 100644
--- a/lib/swoc/src/swoc_file.cc
+++ b/lib/swoc/src/swoc_file.cc
@@ -385,6 +385,7 @@ remove_all(const path &p, std::error_code &ec)
// Invariant - @a p is a directory.
// recursively remove nested files and directories
+ //coverity[toctou : SUPPRESS]
if (nullptr == (dir = opendir(p.c_str()))) {
ec = std::error_code(errno, std::system_category());
return zret;
@@ -416,6 +417,7 @@ bool remove(path const& p, std::error_code &ec) {
} else if (::stat(p.c_str(), &fs) < 0) {
ec = std::error_code(errno, std::system_category());
} else if (S_ISREG(fs.st_mode)) { // regular file, try to remove it!
+ //coverity[toctou : SUPPRESS]
if (unlink(p.c_str()) != 0) {
ec = std::error_code(errno, std::system_category());
}
diff --git a/lib/swoc/src/swoc_ip.cc b/lib/swoc/src/swoc_ip.cc
index 29e7f1d051..301adcaf71 100644
--- a/lib/swoc/src/swoc_ip.cc
+++ b/lib/swoc/src/swoc_ip.cc
@@ -676,11 +676,11 @@ auto
IPMask::mask_for_quad(IP6Addr::quad_type q) -> raw_type {
raw_type cidr = IP6Addr::QUAD_WIDTH;
if (q != 0) {
- auto mask = IP6Addr::QUAD_MASK;
+ IP6Addr::quad_type mask = IP6Addr::QUAD_MASK;
do {
mask <<= 1;
--cidr;
- } while ((q | ~mask) == q);
+ } while ((q & mask) == q);
++cidr; // loop goes exactly 1 too far.
}
return cidr;
@@ -842,18 +842,20 @@ auto IPSrv::assign(const sockaddr *sa) -> self_type & {
bool
IP4Net::load(TextView text) {
- auto idx = text.find('/');
- if (idx != text.npos) {
- if (idx + 1 < text.size()) { // must have something past the separator or
it's bogus.
- IP4Addr addr;
- if (addr.load(text.substr(0, idx))) { // load the address
- IPMask mask;
- text.remove_prefix(idx + 1); // drop address and separator.
- if (mask.load(text)) {
- this->assign(addr, mask);
- return true;
+ if (auto mask_text = text.split_suffix_at('/') ; !mask_text.empty() ) {
+ IPMask mask;
+ bool mask_p = mask.load(mask_text);
+ if (IP4Addr addr; addr.load(text)) {
+ if (!mask_p) {
+ if (IP4Addr m ; m.load(mask_text)) {
+ mask = IPMask::mask_for(m);
+ mask_p = (m == mask.as_ip4()); // must be an actual mask like
address.
}
}
+ if (mask_p) {
+ this->assign(addr, mask);
+ return true;
+ }
}
}
@@ -863,18 +865,20 @@ IP4Net::load(TextView text) {
bool
IP6Net::load(TextView text) {
- auto idx = text.find('/');
- if (idx != text.npos) {
- if (idx + 1 < text.size()) { // must have something past the separator or
it's bogus.
- IP6Addr addr;
- if (addr.load(text.substr(0, idx))) { // load the address
- IPMask mask;
- text.remove_prefix(idx + 1); // drop address and separator.
- if (mask.load(text)) {
- this->assign(addr, mask);
- return true;
+ if (auto mask_text = text.split_suffix_at('/') ; !mask_text.empty() ) {
+ IPMask mask;
+ bool mask_p = mask.load(mask_text);
+ if (IP6Addr addr; addr.load(text)) {
+ if (!mask_p) {
+ if (IP6Addr m ; m.load(mask_text)) {
+ mask = IPMask::mask_for(m);
+ mask_p = (m == mask.as_ip6()); // must be an actual mask like
address.
}
}
+ if (mask_p) {
+ this->assign(addr, mask);
+ return true;
+ }
}
}
@@ -886,11 +890,27 @@ bool
IPNet::load(TextView text) {
if ( auto mask_text = text.split_suffix_at('/') ; !mask_text.empty() ) {
IPMask mask;
- if (mask.load(mask_text)) {
- if (IP6Addr a6; a6.load(text)) { // load the address
+ bool mask_p = mask.load(mask_text);
+
+ if (IP6Addr a6 ; a6.load(text)) { // load the address
+ if (!mask_p) {
+ if (IP6Addr m ; m.load(mask_text)) {
+ mask = IPMask::mask_for(m);
+ mask_p = (m == mask.as_ip6()); // must be an actual mask like
address.
+ }
+ }
+ if (mask_p) {
this->assign(a6, mask);
return true;
- } else if (IP4Addr a4; a4.load(text)) {
+ }
+ } else if (IP4Addr a4 ; a4.load(text)) {
+ if (!mask_p) {
+ if (IP4Addr m ; m.load(mask_text)) {
+ mask = IPMask::mask_for(m);
+ mask_p = (m == mask.as_ip4()); // must be an actual mask like
address.
+ }
+ }
+ if (mask_p) {
this->assign(a4, mask);
return true;
}
@@ -1212,4 +1232,30 @@ IP6Range::NetSource::search_narrower() {
}
}
+bool
+IPRangeView::operator==(IPRange const &r) const {
+ if (_family == r.family()) {
+ if (AF_INET == _family) {
+ return *_raw._4 == r.ip4();
+ } else if (AF_INET6 == _family) {
+ return *_raw._6 == r.ip6();
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+IPRangeView::operator==(IPRangeView::self_type const &that) const {
+ if (_family == that._family) { // different families are not equal
+ if (AF_INET == _family) {
+ return (_raw._4 == that._raw._4) || (*_raw._4 == *that._raw._4);
+ } else if (AF_INET6 == _family) {
+ return (_raw._6 == that._raw._6) || (*_raw._6 == *that._raw._6);
+ }
+ return true;
+ }
+ return false;
+}
+
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/proxy/ControlMatcher.cc b/proxy/ControlMatcher.cc
index 6e072105d0..a633679e97 100644
--- a/proxy/ControlMatcher.cc
+++ b/proxy/ControlMatcher.cc
@@ -651,7 +651,7 @@ template <class Data, class MatchResult>
void
IpMatcher<Data, MatchResult>::Match(sockaddr const *addr, RequestData *rdata,
MatchResult *result) const
{
- if (auto &&[range, data]{*ip_addrs.find(swoc::IPAddr(addr))};
!range.empty()) {
+ if (auto [range, data]{*ip_addrs.find(swoc::IPAddr(addr))}; !range.empty()) {
ink_assert(data != nullptr);
data->UpdateMatch(result, rdata);
}