You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bn...@apache.org on 2022/10/20 20:29:50 UTC
[trafficserver] branch 10-Dev updated: Update to libswoc 1.3.11 (#9152)
This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch 10-Dev
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/10-Dev by this push:
new 0de27c731 Update to libswoc 1.3.11 (#9152)
0de27c731 is described below
commit 0de27c731970ff8b215d3132e502f0a8a184a97f
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Thu Oct 20 15:29:43 2022 -0500
Update to libswoc 1.3.11 (#9152)
* libswoc: Clean up ts::MemSpan
* libswoc: update to 1.3.11
---
lib/swoc/include/swoc/DiscreteRange.h | 39 +++++
lib/swoc/include/swoc/Errata.h | 14 +-
lib/swoc/include/swoc/IntrusiveDList.h | 3 +-
lib/swoc/include/swoc/Lexicon.h | 291 ++++++++++++++++++++++-----------
lib/swoc/include/swoc/MemArena.h | 106 +++++++++---
lib/swoc/include/swoc/MemSpan.h | 122 ++++++++++----
lib/swoc/include/swoc/RBTree.h | 4 +-
lib/swoc/include/swoc/Scalar.h | 51 +++++-
lib/swoc/include/swoc/TextView.h | 101 +++++++-----
lib/swoc/include/swoc/Vectray.h | 36 ++--
lib/swoc/include/swoc/bwf_base.h | 81 +++++----
lib/swoc/include/swoc/bwf_ex.h | 53 +++++-
lib/swoc/include/swoc/swoc_file.h | 41 ++++-
lib/swoc/include/swoc/swoc_ip.h | 86 ++++++----
lib/swoc/include/swoc/swoc_meta.h | 10 +-
lib/swoc/include/swoc/swoc_version.h | 4 +-
lib/swoc/src/Errata.cc | 6 +-
lib/swoc/src/bw_format.cc | 26 ++-
18 files changed, 760 insertions(+), 314 deletions(-)
diff --git a/lib/swoc/include/swoc/DiscreteRange.h b/lib/swoc/include/swoc/DiscreteRange.h
index 503911cac..fa7cf7cb7 100644
--- a/lib/swoc/include/swoc/DiscreteRange.h
+++ b/lib/swoc/include/swoc/DiscreteRange.h
@@ -22,36 +22,75 @@ namespace detail {
/// A set of metafunctions to get extrema from a metric type.
/// These probe for a static member and falls back to @c std::numeric_limits.
/// @{
+
+/** Maximum value.
+ *
+ * @tparam M Metric type.
+ * @return Maximum value for @a M.
+ *
+ * Use @c std::numeric_limits.
+ */
template <typename M>
constexpr auto
maximum(meta::CaseTag<0>) -> M {
return std::numeric_limits<M>::max();
}
+/** Maximum value.
+ *
+ * @tparam M Metric type.
+ * @return Maximum value for @a M.
+ *
+ * Use @c M::MAX
+ */
template <typename M>
constexpr auto
maximum(meta::CaseTag<1>) -> decltype(M::MAX) {
return M::MAX;
}
+/** Maximum value.
+ *
+ * @tparam M Metric type.
+ * @return Maximum value for @a M.
+ */
template <typename M>
constexpr M
maximum() {
return maximum<M>(meta::CaseArg);
}
+/** Minimum value.
+ *
+ * @tparam M Metric type.
+ * @return Minimum value for @a M
+ *
+ * Use @c std::numeric_limits
+ */
template <typename M>
constexpr auto
minimum(meta::CaseTag<0>) -> M {
return std::numeric_limits<M>::min();
}
+/** Minimum value.
+ *
+ * @tparam M Metric type.
+ * @return Minimum value for @a M
+ *
+ * Use @c M::MIN
+ */
template <typename M>
constexpr auto
minimum(meta::CaseTag<1>) -> decltype(M::MIN) {
return M::MIN;
}
+/** Minimum value.
+ *
+ * @tparam M Metric type.
+ * @return Minimum value for @a M
+ */
template <typename M>
constexpr M
minimum() {
diff --git a/lib/swoc/include/swoc/Errata.h b/lib/swoc/include/swoc/Errata.h
index 11675f5bd..77b20b2b0 100644
--- a/lib/swoc/include/swoc/Errata.h
+++ b/lib/swoc/include/swoc/Errata.h
@@ -60,6 +60,9 @@ public:
using code_type = std::error_code; ///< Type for message code.
using severity_type = uint8_t; ///< Underlying type for @c Severity.
+ /// Severity value for an instance.
+ /// This provides conversion to a numeric value, but not from. The result is constructors must be
+ /// passed an explicit serverity, avoiding ambiguity with other possible numeric arguments.
struct Severity {
severity_type _raw; ///< Severity numeric value
@@ -142,6 +145,8 @@ public:
/** Construct with @a text.
*
* @param text Annotation content (literal).
+ * @param severity Local severity.
+ * @param level Nesting level.
*
* @a text is presumed to be stable for the @c Annotation lifetime - this constructor simply copies
* the view.
@@ -280,6 +285,7 @@ public:
template <typename... Args> self_type ¬e_v(std::string_view fmt, std::tuple<Args...> const &args);
/** Append an @c Annotation.
+ * @param severity Local severity.
* @param fmt Format string (@c BufferWriter style).
* @param args Arguments for values in @a fmt.
* @return A reference to this object.
@@ -1225,6 +1231,7 @@ BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, Errata const &);
// Tuple / structured binding support.
namespace std {
+/// @cond INTERNAL_DETAIL
template <size_t IDX, typename R> class tuple_element<IDX, swoc::Rv<R>> { static_assert("swoc:Rv tuple index out of range"); };
template <typename R> class tuple_element<0, swoc::Rv<R>> {
@@ -1238,16 +1245,17 @@ public:
};
template <typename R> class tuple_size<swoc::Rv<R>> : public std::integral_constant<size_t, 2> {};
-
+/// @endcond
} // namespace std
namespace swoc { inline namespace SWOC_VERSION_NS {
// Not sure how much of this is needed, but experimentally all of these were needed in one
// use case or another of structured binding. I wasn't able to make this work if this was
// defined in namespace @c std. Also, because functions can't be partially specialized, it is
-// necessary to use @c constexpr @c if to handle the case. This should roll up nicely when
+// necessary to use @c constexpr @c if to handle the cases. This should roll up nicely when
// compiled.
+/// @cond INTERNAL_DETAIL
template <size_t IDX, typename R>
typename std::tuple_element<IDX, swoc::Rv<R>>::type &
get(swoc::Rv<R> &&rv) {
@@ -1283,5 +1291,5 @@ get(swoc::Rv<R> const &rv) {
// Shouldn't need this due to the @c static_assert but the Intel compiler requires it.
throw std::domain_error("Errata index value out of bounds");
}
-
+/// @endcond
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/lib/swoc/include/swoc/IntrusiveDList.h b/lib/swoc/include/swoc/IntrusiveDList.h
index 3efd678ce..0287a2c1f 100644
--- a/lib/swoc/include/swoc/IntrusiveDList.h
+++ b/lib/swoc/include/swoc/IntrusiveDList.h
@@ -878,6 +878,7 @@ IntrusiveDList<L>::clear() -> self_type & {
}
namespace detail {
+/// @cond INTERNAL_DETAIL
// Make @c apply more convenient by allowing the function to take a reference type or pointer type
// to the container elements. The pointer type is the base, plus a shim to convert from a reference
// type functor to a pointer pointer type. The complex return type definition forces only one, but
@@ -911,5 +912,5 @@ auto
IntrusiveDList<L>::apply(F &&f) -> self_type & {
return detail::Intrusive_DList_Apply(*this, f);
}
-
+/// @endcond
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/lib/swoc/include/swoc/Lexicon.h b/lib/swoc/include/swoc/Lexicon.h
index 90ea861be..df5c11287 100644
--- a/lib/swoc/include/swoc/Lexicon.h
+++ b/lib/swoc/include/swoc/Lexicon.h
@@ -40,12 +40,12 @@ what(std::string_view const &fmt, Args &&... args) {
} // namespace detail
/// Policy template use to specify the hash function for the integral type of @c Lexicon.
-/// The default is to cast to the required hash value type, which is usually sufficient.
-/// In some cases the cast doesn't work and this must be specialized.
+/// The default is @c std::hash but that can be overridden by specializing this method.
template <typename E>
-uintmax_t
+size_t
Lexicon_Hash(E e) {
- return static_cast<uintmax_t>(e);
+ static constexpr std::hash<E> hasher;
+ return hasher(e);
}
/** A bidirectional mapping between names and enumeration values.
@@ -77,6 +77,15 @@ protected:
struct Item;
public:
+ /// An association of an enumeration value and a name.
+ /// @ note Used for initializer lists that have just a primary value.
+ using Pair = std::tuple<E, std::string_view>;
+
+ /// Index in @c Pair for the enumeration value.
+ static constexpr auto VALUE_IDX = 0;
+ /// Index in @c Pair for name.
+ static constexpr auto NAME_IDX = 1;
+
/** A function to be called if a value is not found to provide a default name.
* @param value The value.
* @return A name for the value.
@@ -102,9 +111,6 @@ public:
*/
using DefaultHandler = std::variant<std::monostate, E, std::string_view, UnknownNameHandler, UnknownValueHandler>;
- /// Used for initializer lists that have just a primary value.
- using Pair = std::tuple<E, std::string_view>;
-
/// Element of an initializer list that contains secondary names.
struct Definition {
const E &value; ///< Value for definition.
@@ -124,7 +130,7 @@ public:
* The first value is the primary value and is required. Subsequent values are optional
* and become secondary values.
*
- * The default handlers are optional can be be omitted. If so, exceptions are thrown when values
+ * The default handlers are optional can be omitted. If so, exceptions are thrown when values
* or names not in the @c Lexicon are used. See @c set_default for more details.
*
* @see set_default.
@@ -140,7 +146,7 @@ public:
*
* Each item in the intializers must be a @c Pair, that is a name and a value.
*
- * The default handlers are optional can be be omitted. If so, exceptions are thrown when values
+ * The default handlers are optional can be omitted. If so, exceptions are thrown when values
* or names not in the @c Lexicon are used. See @c set_default for more details.
*
* @see set_default.
@@ -153,7 +159,7 @@ public:
* @param handler_1 A default handler.
* @param handler_2 A default handler.
*
- * @a handler_2 is optional can be be omitted. The argument values are the same as for
+ * @a handler_2 is optional can be omitted. The argument values are the same as for
* @c set_default.
*
* @see set_default.
@@ -167,7 +173,7 @@ public:
* @param value Value to look up.
* @return The name for @a value.
*/
- std::string_view operator[](E value) const;
+ std::string_view operator[](E const& value) const;
/** Get the value for a @a name.
*
@@ -229,43 +235,59 @@ public:
/// Get the number of values with definitions.
size_t count() const;
+protected:
+ /// Common features of container iterators.
+ class base_iterator {
+ using self_type = base_iterator;
+ public:
+ using value_type = const Pair; ///< Iteration value.
+ using pointer = value_type *; ///< Pointer to iteration value.
+ using reference = value_type &; ///< Reference to iteration value.
+ using difference_type = ptrdiff_t; ///< Type of difference between iterators.
+ using iterator_category = std::bidirectional_iterator_tag; ///< Concepts for iterator.
+ /// Default constructor (invalid iterator)
+ base_iterator() = default;
+ /// Dereference.
+ reference operator*() const;
+ /// Dereference.
+ pointer operator->() const;
+ /// Equality.
+ bool operator==(self_type const &that) const;
+ /// Inequality.
+ bool operator!=(self_type const &that) const;
+
+ protected:
+ base_iterator(Item const * item) : _item(item) {}
+
+ const Item *_item{nullptr}; ///< Current location in the container.
+ };
+
+public:
+
/** Iterator over pairs of values and primary name pairs.
- * Value is a 2-tuple of the enumeration type and the primary name.
+ * The value type is a @c Pair with the value and name.
*/
- class const_iterator {
- using self_type = const_iterator;
+ class value_iterator : public base_iterator {
+ using super_type = base_iterator;
+ using self_type = value_iterator;
public:
- using value_type = const Pair;
- using pointer = value_type *;
- using reference = value_type &;
- using difference_type = ptrdiff_t;
- using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = typename super_type::value_type;
+ using pointer = typename super_type::pointer;
+ using reference = typename super_type::reference;
/// Default constructor.
- const_iterator() = default;
+ value_iterator() = default;
/// Copy constructor.
- const_iterator(self_type const &that) = default;
-
- /// Move construcgtor.
- const_iterator(self_type &&that) = default;
-
- /// Dereference.
- reference operator*() const;
+ value_iterator(self_type const &that) = default;
- /// Dereference.
- pointer operator->() const;
+ /// Move constructor.
+ value_iterator(self_type &&that) = default;
/// Assignment.
self_type &operator=(self_type const &that) = default;
- /// Equality.
- bool operator==(self_type const &that) const;
-
- /// Inequality.
- bool operator!=(self_type const &that) const;
-
/// Increment.
self_type &operator++();
@@ -279,18 +301,50 @@ public:
self_type operator--(int);
protected:
- const_iterator(const Item *item); ///< Internal constructor.
+ value_iterator(const Item *item) : super_type(item) {}; ///< Internal constructor.
- /// Update the internal values after changing the iterator location.
- void update();
+ friend Lexicon;
+ };
- const Item *_item{nullptr}; ///< Current location in the container.
- typename std::remove_const<value_type>::type _v; ///< Synthesized value for dereference.
+ class name_iterator : public base_iterator {
+ private:
+ using self_type = name_iterator;
+ using super_type = base_iterator;
+ public:
+ /// Default constructor.
+ name_iterator() = default;
+
+ /// Copy constructor.
+ name_iterator(self_type const &that) = default;
+
+ /// Move constructor.
+ name_iterator(self_type &&that) = default;
+
+ /// Assignment.
+ self_type &operator=(self_type const &that) = default;
+
+ /// Increment.
+ self_type &operator++();
+
+ /// Increment.
+ self_type operator++(int);
+
+ /// Decrement.
+ self_type &operator--();
+
+ /// Decrement.
+ self_type operator--(int);
+
+ protected:
+ name_iterator(const Item *item) : super_type(item) {}; ///< Internal constructor.
friend Lexicon;
};
- // Only constant iterator allowed, values cannot be modified.
+ /// Iterator over values (each with a primary name).
+ using const_iterator = value_iterator;
+ /// Iterator over values.
+ /// @note All iteration is over constant pairs, no modification is possible.
using iterator = const_iterator;
/// Iteration begin.
@@ -299,6 +353,34 @@ public:
/// Iteration end.
const_iterator end() const;
+ /// Iteration over names - every value/name pair.
+ name_iterator begin_names() const { return { _by_name.begin() }; }
+ /// Iteration over names - every value/name pair.
+ name_iterator end_names() const { return { _by_name.end() }; }
+
+ /// @cond INTERNAL
+ // Helper struct to return to enable container iteration for names.
+ struct ByNameHelper {
+ self_type const & _lexicon;
+ ByNameHelper(self_type const & self) : _lexicon(self) {}
+ name_iterator begin() const { return _lexicon.begin_names(); }
+ name_iterator end() const { return _lexicon.end_names(); }
+ };
+ /// @endcond
+
+ /** Enable container iteration by name.
+ * The return value is a tempoary of indeterminate type that provides @c begin and @c end methods which
+ * return name based iterators for @a this. This is useful for container based iteration. E.g. to iterate
+ * over all of the value/name pairs,
+ * @code
+ * for ( auto const & pair : lexicon.by_names()) {
+ * // code
+ * }
+ * @endcode
+ * @return Temporary.
+ */
+ ByNameHelper by_names() const { return { *this }; }
+
protected:
/// Handle providing a default name.
using NameDefault = std::variant<std::monostate, std::string_view, UnknownValueHandler>;
@@ -307,18 +389,21 @@ protected:
/// Visitor functor for handling @c NameDefault.
struct NameDefaultVisitor {
- E _value;
+ E _value; ///< Value to use for default.
+ /// Visitor - invalid value type.
std::string_view
operator()(std::monostate const &) const {
- throw std::domain_error(detail::what("Lexicon: invalid enumeration value {}", static_cast<int>(_value)).data());
+ throw std::domain_error("Lexicon: invalid enumeration value");
}
+ /// Visitor - literal string.
std::string_view
operator()(std::string_view const &name) const {
return name;
}
+ /// Visitor - string generator.
std::string_view
operator()(UnknownValueHandler const &handler) const {
return handler(_value);
@@ -327,18 +412,21 @@ protected:
/// Visitor functor for handling @c ValueDefault.
struct ValueDefaultVisitor {
- std::string_view _name;
+ std::string_view _name; ///< Name of visited pair.
+ /// Vistor - invalid value.
E
operator()(std::monostate const &) const {
throw std::domain_error(detail::what("Lexicon: Unknown name \"{}\"", _name).data());
}
+ /// Visitor - value.
E
operator()(E const &value) const {
return value;
}
+ /// Visitor - value generator.
E
operator()(UnknownNameHandler const &handler) const {
return handler(_name);
@@ -356,40 +444,33 @@ protected:
*/
Item(E value, std::string_view name);
- E _value; ///< Definition value.
- std::string_view _name; ///< Definition name
+ Pair _payload; ///< Enumeration and name.
- /// Intrusive linkage for name lookup.
+ /// @cond INTERNAL_DETAIL
+ // Intrusive list linkage support.
struct NameLinkage {
Item *_next{nullptr};
Item *_prev{nullptr};
static Item *&next_ptr(Item *);
-
static Item *&prev_ptr(Item *);
-
static std::string_view key_of(Item *);
-
static uint32_t hash_of(std::string_view s);
-
static bool equal(std::string_view const &lhs, std::string_view const &rhs);
} _name_link;
- /// Intrusive linkage for value lookup.
+ // Intrusive linkage for value lookup.
struct ValueLinkage {
Item *_next{nullptr};
Item *_prev{nullptr};
static Item *&next_ptr(Item *);
-
static Item *&prev_ptr(Item *);
-
static E key_of(Item *);
-
- static uintmax_t hash_of(E);
-
+ static size_t hash_of(E);
static bool equal(E lhs, E rhs);
} _value_link;
+ /// @endcond
};
/// Copy @a name in to local storage.
@@ -411,8 +492,9 @@ protected:
// ----
// Item
-template <typename E> Lexicon<E>::Item::Item(E value, std::string_view name) : _value(value), _name(name) {}
+template <typename E> Lexicon<E>::Item::Item(E value, std::string_view name) : _payload(value, name) {}
+/// @cond INTERNAL_DETAIL
template <typename E>
auto
Lexicon<E>::Item::NameLinkage::next_ptr(Item *item) -> Item *& {
@@ -440,13 +522,13 @@ Lexicon<E>::Item::ValueLinkage::prev_ptr(Item *item) -> Item *& {
template <typename E>
std::string_view
Lexicon<E>::Item::NameLinkage::key_of(Item *item) {
- return item->_name;
+ return std::get<NAME_IDX>(item->_payload);
}
template <typename E>
E
Lexicon<E>::Item::ValueLinkage::key_of(Item *item) {
- return item->_value;
+ return std::get<VALUE_IDX>(item->_payload);
}
template <typename E>
@@ -456,9 +538,8 @@ Lexicon<E>::Item::NameLinkage::hash_of(std::string_view s) {
}
template <typename E>
-uintmax_t
+size_t
Lexicon<E>::Item::ValueLinkage::hash_of(E value) {
- // In almost all cases, the values will be (roughly) sequential, so an identity hash works well.
return Lexicon_Hash<E>(value);
}
@@ -473,6 +554,7 @@ bool
Lexicon<E>::Item::ValueLinkage::equal(E lhs, E rhs) {
return lhs == rhs;
}
+/// @endcond
// -------
// Lexicon
@@ -517,10 +599,9 @@ Lexicon<E>::localize(std::string_view const &name) {
template <typename E>
std::string_view
-Lexicon<E>::operator[](E value) const {
- auto spot = _by_value.find(value);
- if (spot != _by_value.end()) {
- return spot->_name;
+Lexicon<E>::operator[](E const& value) const {
+ if ( auto spot = _by_value.find(value) ; spot != _by_value.end()) {
+ return std::get<NAME_IDX>(spot->_payload);
}
return std::visit(NameDefaultVisitor{value}, _name_default);
}
@@ -528,9 +609,8 @@ Lexicon<E>::operator[](E value) const {
template <typename E>
E
Lexicon<E>::operator[](std::string_view const &name) const {
- auto spot = _by_name.find(name);
- if (spot != _by_name.end()) {
- return spot->_value;
+ if ( auto spot = _by_name.find(name) ; spot != _by_name.end()) {
+ return std::get<VALUE_IDX>(spot->_payload);
}
return std::visit(ValueDefaultVisitor{name}, _value_default);
}
@@ -541,7 +621,7 @@ Lexicon<E>::define(E value, const std::initializer_list<std::string_view> &names
if (names.size() < 1) {
throw std::invalid_argument("A defined value must have at least a primary name");
}
- for (auto name : names) {
+ for (auto const& name : names) {
if (_by_name.find(name) != _by_name.end()) {
throw std::invalid_argument(detail::what("Duplicate name '{}' in Lexicon", name));
}
@@ -566,7 +646,7 @@ Lexicon<E>::define(E value, Args &&... names) -> self_type & {
template <typename E>
auto
Lexicon<E>::define(const Pair &pair) -> self_type & {
- return this->define(std::get<0>(pair), {std::get<1>(pair)});
+ return this->define(std::get<VALUE_IDX>(pair), {std::get<NAME_IDX>(pair)});
}
template <typename E>
@@ -618,54 +698,69 @@ Lexicon<E>::end() const -> const_iterator {
// Iterators
template <typename E>
-void
-Lexicon<E>::const_iterator::update() {
- std::get<0>(_v) = _item->_value;
- std::get<1>(_v) = _item->_name;
+auto
+Lexicon<E>::base_iterator::operator*() const -> reference {
+ return _item->_payload;
}
-template <typename E> Lexicon<E>::const_iterator::const_iterator(const Item *item) : _item(item) {
- if (_item) {
- this->update();
- };
+template <typename E>
+auto
+Lexicon<E>::base_iterator::operator->() const -> pointer {
+ return &(_item->_payload);
+}
+
+template <typename E>
+bool
+Lexicon<E>::base_iterator::operator==(self_type const &that) const {
+ return _item == that._item;
+}
+
+template <typename E>
+bool
+Lexicon<E>::base_iterator::operator!=(self_type const &that) const {
+ return _item != that._item;
}
template <typename E>
auto
-Lexicon<E>::const_iterator::operator*() const -> reference {
- return _v;
+Lexicon<E>::value_iterator::operator++() -> self_type & {
+ super_type::_item = super_type::_item->_value_link._next;
+ return *this;
}
template <typename E>
auto
-Lexicon<E>::const_iterator::operator->() const -> pointer {
- return &_v;
+Lexicon<E>::value_iterator::operator++(int) -> self_type {
+ self_type tmp{*this};
+ ++*this;
+ return tmp;
}
template <typename E>
-bool
-Lexicon<E>::const_iterator::operator==(self_type const &that) const {
- return _item == that._item;
+auto
+Lexicon<E>::value_iterator::operator--() -> self_type & {
+ super_type::_item = super_type::_item->_value_link->_prev;
+ return *this;
}
template <typename E>
-bool
-Lexicon<E>::const_iterator::operator!=(self_type const &that) const {
- return _item != that._item;
+auto
+Lexicon<E>::value_iterator::operator--(int) -> self_type {
+ self_type tmp;
+ ++*this;
+ return tmp;
}
template <typename E>
auto
-Lexicon<E>::const_iterator::operator++() -> self_type & {
- if (nullptr != (_item = _item->_value_link._next)) {
- this->update();
- }
+Lexicon<E>::name_iterator::operator++() -> self_type & {
+ super_type::_item = super_type::_item->_name_link._next;
return *this;
}
template <typename E>
auto
-Lexicon<E>::const_iterator::operator++(int) -> self_type {
+Lexicon<E>::name_iterator::operator++(int) -> self_type {
self_type tmp{*this};
++*this;
return tmp;
@@ -673,16 +768,14 @@ Lexicon<E>::const_iterator::operator++(int) -> self_type {
template <typename E>
auto
-Lexicon<E>::const_iterator::operator--() -> self_type & {
- if (nullptr != (_item = _item->_value_link->_prev)) {
- this->update();
- }
+Lexicon<E>::name_iterator::operator--() -> self_type & {
+ super_type::_item = super_type::_item->_name_link->_prev;
return *this;
}
template <typename E>
auto
-Lexicon<E>::const_iterator::operator--(int) -> self_type {
+Lexicon<E>::name_iterator::operator--(int) -> self_type {
self_type tmp;
++*this;
return tmp;
diff --git a/lib/swoc/include/swoc/MemArena.h b/lib/swoc/include/swoc/MemArena.h
index a68e9be35..a4dc40929 100644
--- a/lib/swoc/include/swoc/MemArena.h
+++ b/lib/swoc/include/swoc/MemArena.h
@@ -36,7 +36,7 @@ class MemArena
using self_type = MemArena; ///< Self reference type.
public:
- static constexpr size_t DEFAULT_ALIGNMENT{1};
+ static constexpr size_t DEFAULT_ALIGNMENT{1}; ///< Default memory alignment.
/// Simple internal arena block of memory. Maintains the underlying memory.
struct Block {
@@ -98,7 +98,7 @@ public:
bool is_full() const;
protected:
- friend MemArena;
+ friend MemArena; ///< Container.
/** Override @c operator @c delete.
*
@@ -139,15 +139,18 @@ public:
size_t allocated{0}; ///< Current allocated (in use) bytes.
struct Linkage {
+ /// @cond INTERNAL_DETAIL
Block *_next{nullptr};
Block *_prev{nullptr};
static Block *&next_ptr(Block *);
static Block *&prev_ptr(Block *);
- } _link;
+ /// @endcond
+ } _link; ///< Intrusive list support.
};
+ /// Intrusive list of blocks.
using BlockList = IntrusiveDList<Block::Linkage>;
/** Construct with reservation hint.
@@ -184,9 +187,11 @@ public:
/// Destructor.
~MemArena();
- self_type &operator=(self_type const &that) = delete;
+ /// No copy assignment.
+ self_type & operator=(self_type const & that) = delete;
- self_type &operator=(self_type &&that);
+ /// Move assignment.
+ self_type & operator=(self_type &&that);
/** Make a self-contained instance.
*
@@ -309,9 +314,30 @@ public:
/// @return The amount of free space.
size_t remaining() const;
+ /** Get aligned and sized remnant.
+ *
+ * @tparam T Element type.
+ * @param n Number of instances of @a T
+ * @return A span that is in the remnant, correctly aligned with minimal padding.
+ *
+ * This is guaranteed to be the same bytes as if @c alloc<T> was called. The returned span will
+ * always be the specified size, the remnant will be expanded as needed.
+ */
+ template <typename T> MemSpan<T> remnant_span(size_t n);
+
/// @return Contiguous free space in the current internal block.
MemSpan<void> remnant();
+ /** Get an aligned remnant.
+ *
+ * @param n Remnant size.
+ * @param align Memory alignment (default 1, must be power of 2).
+ * @return Space in the remnant with minimal alignment padding.
+ *
+ * @note This will always return a span of @a n bytes, the remnant will be expanded as needed.
+ */
+ MemSpan<void> remnant(size_t n, size_t align = DEFAULT_ALIGNMENT);
+
/** Require @a n bytes of contiguous memory to be available for allocation.
*
* @param n Number of bytes.
@@ -338,19 +364,20 @@ public:
*/
size_t reserved_size() const;
- using const_iterator = BlockList::const_iterator;
- using iterator = const_iterator; // only const iteration allowed on blocks.
+ using const_iterator = BlockList::const_iterator; ///< Constant element iteration.
+ using iterator = const_iterator; ///< Element iteration.
- /// Iterate over active blocks.
+ /// First active block.
const_iterator begin() const;
+ /// After Last active block.
const_iterator end() const;
- /// Iterator over frozen blocks.
+ /// First frozen block.
const_iterator frozen_begin() const;
+ /// After last frozen block.
const_iterator frozen_end() const;
-
protected:
/** Internally allocates a new block of memory of size @a n bytes.
*
@@ -454,8 +481,13 @@ public:
/// Drop all items in the free list.
void clear();
+
+ /// Access the wrapped arena directly.
+ MemArena & arena();
};
-// Implementation
+
+// --- Implementation ---
+/// @cond INTERNAL_DETAIL
inline auto
MemArena::Block::Linkage::next_ptr(Block *b) -> Block *& {
@@ -508,20 +540,6 @@ MemArena::Block::alloc(size_t n, size_t align) {
return zret;
}
-template <typename T>
-MemSpan<T>
-MemArena::alloc_span(size_t n) {
- return this->alloc(sizeof(T) * n, size_t{alignof(T)}).rebind<T>();
-}
-
-template <typename T, typename... Args>
-T *
-MemArena::make(Args &&... args) {
- return new (this->alloc(sizeof(T)).data()) T(std::forward<Args>(args)...);
-}
-
-inline MemArena::MemArena(size_t n) : _reserve_hint(n) {}
-
inline MemSpan<void>
MemArena::Block::remnant() {
return {this->data() + allocated, this->remaining()};
@@ -544,10 +562,40 @@ MemArena::Block::operator delete([[maybe_unused]] void *ptr, void *place) noexce
inline size_t
MemArena::Block::align_padding(void const *ptr, size_t align) {
- auto delta = uintptr_t(ptr) & (size_t(align) - 1);
- return delta ? size_t(align) - delta : delta;
+ if (auto delta = uintptr_t(ptr) & (align - 1) ; delta > 0) {
+ return align - delta;
+ }
+ return 0;
+}
+
+inline MemArena::MemArena(size_t n) : _reserve_hint(n) {}
+
+template <typename T>
+MemSpan<T>
+MemArena::alloc_span(size_t n) {
+ return this->alloc(sizeof(T) * n, alignof(T)).rebind<T>();
}
+template <typename T, typename... Args>
+T *
+MemArena::make(Args &&... args) {
+ return new (this->alloc(sizeof(T), alignof(T)).data()) T(std::forward<Args>(args)...);
+}
+
+template <typename T>
+MemSpan<T>
+MemArena::remnant_span(size_t n) {
+ auto span = this->require(sizeof(T) * n, alignof(T)).remnant();
+ return span.remove_prefix(Block::align_padding(span.data(), alignof(T))).rebind<T>();
+}
+
+template <>
+inline MemSpan<void>
+MemArena::remnant_span<void>(size_t n) { return this->require(n).remnant().prefix(n); }
+
+inline MemSpan<void>
+MemArena::remnant(size_t n, size_t align) { return this->require(n, align).remnant().prefix(n); }
+
inline size_t
MemArena::size() const {
return _active_allocated;
@@ -626,4 +674,8 @@ FixedArena<T>::clear() {
_list._next = nullptr;
}
+template < typename T > MemArena & FixedArena<T>::arena() { return _arena; }
+
+/// @endcond INTERNAL_DETAIL
+
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/lib/swoc/include/swoc/MemSpan.h b/lib/swoc/include/swoc/MemSpan.h
index be1e6bf0e..726211e6b 100644
--- a/lib/swoc/include/swoc/MemSpan.h
+++ b/lib/swoc/include/swoc/MemSpan.h
@@ -21,6 +21,7 @@
#include <exception>
#include "swoc/swoc_version.h"
+#include "swoc/Scalar.h"
namespace swoc { inline namespace SWOC_VERSION_NS {
/** A span of contiguous piece of memory.
@@ -53,9 +54,9 @@ protected:
size_t _count = 0; ///< Number of elements.
public:
- using value_type = T;
- using iterator = T *;
- using const_iterator = T const *;
+ using value_type = T; ///< Element type for span.
+ using iterator = T *; ///< Iterator.
+ using const_iterator = T const *; ///< Constant iterator.
/// Default constructor (empty buffer).
constexpr MemSpan() = default;
@@ -82,7 +83,7 @@ public:
* @tparam N Number of elements in the array.
* @param a The array.
*/
- template <auto N> MemSpan(T (&a)[N]);
+ template <auto N> constexpr MemSpan(T (&a)[N]);
/** Construct from constant @c std::array.
*
@@ -136,7 +137,7 @@ public:
@return @c true if the contents of @a that are the same as the content of @a this,
@c false otherwise.
*/
- bool operator==(self_type const &that) const;
+ constexpr bool operator==(self_type const &that) const;
/** Identical.
@@ -149,7 +150,7 @@ public:
@return @c true if @a that does not refer to the same span as @a this,
@c false otherwise.
*/
- bool operator!=(self_type const &that) const;
+ constexpr bool operator!=(self_type const &that) const;
/// Assignment - the span is copied, not the content.
self_type &operator=(self_type const &that) = default;
@@ -167,24 +168,27 @@ public:
/// Check for empty span (no content).
/// @see operator bool
- bool empty() const;
+ constexpr bool empty() const;
/// @name Accessors.
//@{
/// Pointer to the first element in the span.
- T *begin() const;
+ constexpr T *begin() const;
/// Pointer to first element not in the span.
- T *end() const;
+ constexpr T *end() const;
/// Number of elements in the span
- size_t count() const;
+ constexpr size_t count() const;
/// Number of bytes in the span.
size_t size() const;
- /// Pointer to memory in the span.
- T *data() const;
+ /// @return Pointer to memory in the span.
+ T * data() const;
+
+ /// @return Pointer to immediate after memory in the span.
+ constexpr T *data_end() const;
/** Access the first element in the span.
*
@@ -404,9 +408,9 @@ public:
size_t size() const;
/// Pointer to memory in the span.
- value_type *data() const;
+ constexpr value_type *data() const;
- /// Pointer to memory in the span.
+ /// Pointer to just after memory in the span.
value_type *data_end() const;
/** Create a new span for a different type @a V on the same memory.
@@ -478,6 +482,26 @@ public:
*/
constexpr self_type subspan(size_t offset, size_t count) const;
+ /** Align span for a type.
+ *
+ * @tparam T Alignment type.
+ * @return A suffix of the span suitably aligned for @a T.
+ *
+ * The minimum amount of space is removed from the front to yield an aligned span. If the span is not large
+ * enough to perform the alignment, the pointer is aligned and the size reduced to zero (empty).
+ */
+ template <typename T> self_type align() const;
+
+ /** Force memory alignment.
+ *
+ * @param n Alignment size (must be power of 2).
+ * @return An aligned span.
+ *
+ * The minimum amount of space is removed from the front to yield an aligned span. If the span is not large
+ * enough to perform the alignment, the pointer is aligned and the size reduced to zero (empty).
+ */
+ self_type align(size_t n) const;
+
/** Return a view of the memory.
*
* @return A @c string_view covering the span contents.
@@ -488,8 +512,7 @@ public:
// -- Implementation --
namespace detail {
-/// pointer distance calculations for all types, @b including @c <void*>.
-/// This is useful in templates.
+/// @cond INTERNAL_DETAIL
inline size_t
ptr_distance(void const *first, void const *last) {
return static_cast<const char *>(last) - static_cast<const char *>(first);
@@ -505,6 +528,7 @@ inline void *
ptr_add(void *ptr, size_t count) {
return static_cast<char *>(ptr) + count;
}
+/// @endcond
/** Meta Function to check the type compatibility of two spans..
*
@@ -615,36 +639,49 @@ memcpy(MemSpan<void> &span, std::string_view view) {
return std::memcpy(span.data(), view.data(), std::min(view.size(), view.size()));
}
-using std::memcpy;
using std::memcpy;
+/** Set contents of a span to a fixed @a value.
+ *
+ * @tparam T Span type.
+ * @param dst Span to change.
+ * @param value Source value.
+ * @return
+ */
template <typename T>
inline MemSpan<T> const &
-memset(MemSpan<T> const &dst, T const &t) {
+memset(MemSpan<T> const &dst, T const &value) {
for (auto &e : dst) {
- e = t;
+ e = value;
}
return dst;
}
+/// @cond INTERNAL_DETAIL
+
+// Optimization for @c char.
inline MemSpan<char> const &
memset(MemSpan<char> const &dst, char c) {
std::memset(dst.data(), c, dst.size());
return dst;
}
+// Optimization for @c unsigned @c char
inline MemSpan<unsigned char> const &
memset(MemSpan<unsigned char> const &dst, unsigned char c) {
std::memset(dst.data(), c, dst.size());
return dst;
}
+// Optimization for @c char.
inline MemSpan<void> const &
memset(MemSpan<void> const &dst, char c) {
std::memset(dst.data(), c, dst.size());
return dst;
}
+/// @endcond
+
using std::memset;
// --- MemSpan<T> ---
@@ -653,7 +690,7 @@ template <typename T> constexpr MemSpan<T>::MemSpan(T *ptr, size_t count) : _ptr
template <typename T> constexpr MemSpan<T>::MemSpan(T *first, T *last) : _ptr{first}, _count{detail::ptr_distance(first, last)} {}
-template <typename T> template <auto N> MemSpan<T>::MemSpan(T (&a)[N]) : _ptr{a}, _count{N} {}
+template <typename T> template <auto N> constexpr MemSpan<T>::MemSpan(T (&a)[N]) : _ptr{a}, _count{N} {}
template <typename T> constexpr MemSpan<T>::MemSpan(std::nullptr_t) {}
@@ -691,13 +728,13 @@ MemSpan<T>::is_same(self_type const &that) const {
}
template <typename T>
-bool
+constexpr bool
MemSpan<T>::operator==(self_type const &that) const {
return _count == that._count && (_ptr == that._ptr || 0 == memcmp(_ptr, that._ptr, this->size()));
}
template <typename T>
-bool
+constexpr bool
MemSpan<T>::operator!=(self_type const &that) const {
return !(*this == that);
}
@@ -712,13 +749,13 @@ template <typename T> MemSpan<T>::operator bool() const {
return _count != 0;
}
-template <typename T>
+template <typename T> constexpr
bool
MemSpan<T>::empty() const {
return _count == 0;
}
-template <typename T>
+template <typename T> constexpr
T *
MemSpan<T>::begin() const {
return _ptr;
@@ -730,7 +767,13 @@ MemSpan<T>::data() const {
return _ptr;
}
-template <typename T>
+template <typename T> constexpr
+T *
+MemSpan<T>::data_end() const {
+ return _ptr + _count;
+}
+
+template <typename T> constexpr
T *
MemSpan<T>::end() const {
return _ptr + _count;
@@ -742,7 +785,7 @@ MemSpan<T>::operator[](size_t idx) const {
return _ptr[idx];
}
-template <typename T>
+template <typename T> constexpr
size_t
MemSpan<T>::count() const {
return _count;
@@ -760,14 +803,14 @@ MemSpan<T>::contains(T const *ptr) const {
return _ptr <= ptr && ptr < _ptr + _count;
}
-template <typename T>
-constexpr auto
+template <typename T> constexpr
+auto
MemSpan<T>::prefix(size_t count) const -> self_type {
return {_ptr, std::min(count, _count)};
}
-template <typename T>
-constexpr auto
+template <typename T> constexpr
+auto
MemSpan<T>::first(size_t count) const -> self_type {
return this->prefix(count);
}
@@ -781,8 +824,8 @@ MemSpan<T>::remove_prefix(size_t count) -> self_type & {
return *this;
}
-template <typename T>
-constexpr auto
+template <typename T> constexpr
+auto
MemSpan<T>::suffix(size_t count) const -> self_type {
count = std::min(_count, count);
return {(_ptr + _count) - count, count};
@@ -821,7 +864,7 @@ MemSpan<T>::back() {
template <typename T>
template <typename F>
-MemSpan<T> &
+typename MemSpan<T>::self_type &
MemSpan<T>::apply(F &&f) {
for (auto &item : *this) {
f(item);
@@ -905,7 +948,7 @@ MemSpan<void>::empty() const {
return _size == 0;
}
-inline void *
+inline constexpr void *
MemSpan<void>::data() const {
return _ptr;
}
@@ -963,6 +1006,17 @@ MemSpan<void>::remove_suffix(size_t count) {
return *this;
}
+template <typename T>
+MemSpan<void>::self_type
+MemSpan<void>::align() const { return this->align(alignof(T)); }
+
+inline MemSpan<void>::self_type
+MemSpan<void>::align(size_t n) const {
+ auto p = uintptr_t(_ptr);
+ auto padding = p & (n - 1);
+ return { reinterpret_cast<void*>(p + padding), _size - std::min<uintptr_t>(_size, padding) };
+}
+
template <typename U>
MemSpan<U>
MemSpan<void>::rebind() const {
diff --git a/lib/swoc/include/swoc/RBTree.h b/lib/swoc/include/swoc/RBTree.h
index f391e2d0d..2594e6f42 100644
--- a/lib/swoc/include/swoc/RBTree.h
+++ b/lib/swoc/include/swoc/RBTree.h
@@ -59,6 +59,7 @@ struct RBNode {
/// @return The color of the node.
Color color() const;
+ /// @return The left most descendant of @a this, or @a null ptr if no left child.
self_type *left_most_descendant() const;
/** Reverse a direction
@@ -182,11 +183,12 @@ struct RBNode {
/// Support for @c IntrusiveDList
struct Linkage {
+ /// @return Reference to internal pointer to the next element.
static self_type *&
next_ptr(self_type *t) {
return swoc::ptr_ref_cast<self_type>(t->_next);
}
-
+ /// @return Reference to the internal pointer to the previoius element.
static self_type *&
prev_ptr(self_type *t) {
return swoc::ptr_ref_cast<self_type>(t->_prev);
diff --git a/lib/swoc/include/swoc/Scalar.h b/lib/swoc/include/swoc/Scalar.h
index 5191eefce..640e6b926 100644
--- a/lib/swoc/include/swoc/Scalar.h
+++ b/lib/swoc/include/swoc/Scalar.h
@@ -195,7 +195,7 @@ public:
/// @cond INTERNAL_DETAIL
// Assignment from internal rounding structures.
// Conversion constructor.
- constexpr Scalar(detail::scalar_round_up_t<N, C, T> const &that);
+ constexpr Scalar(detail::scalar_round_up_t<N, C, T> const &v);
// Conversion constructor.
constexpr Scalar(detail::scalar_round_down_t<N, C, T> const &that);
@@ -240,7 +240,7 @@ public:
*/
template <typename I> self_type &operator=(detail::scalar_unit_round_down_t<I> n);
- /** Internal method to assign a differently scaled SCALR to be rounded up.
+ /** Internal method to assign a differently scaled SCALAR to be rounded up.
*
* @param v The embedding of the value to be scaled.
* @return @a this
@@ -250,7 +250,7 @@ public:
*/
self_type &operator=(detail::scalar_round_up_t<N, C, T> v);
- /** Internal method to assign a differently scaled SCALR to be rounded down.
+ /** Internal method to assign a differently scaled SCALAR to be rounded down.
*
* @param v The embedding of the value to be scaled.
* @return @a this
@@ -303,6 +303,15 @@ public:
/// the @c scale_up or @c scale_down casts must be used to indicate the rounding direction.
self_type &operator+=(self_type const &that);
+ /** Cross scale addition.
+ *
+ * @tparam S Source scale.
+ * @tparam I Source raw type.
+ * @param that Value.
+ * @return @a this
+ *
+ * @a that is scaled as needed to be added to @a this.
+ */
template <intmax_t S, typename I> self_type &operator+=(Scalar<S, I, T> const &that);
/// @cond INTERNAL_DETAIL
@@ -339,6 +348,15 @@ public:
/// the @c scale_up or @c scale_down casts must be used to indicate the rounding direction.
self_type &operator-=(self_type const &that);
+ /** Subtraction.
+ *
+ * @tparam S Scale.
+ * @tparam I Raw type.
+ * @param that Value to subtract.
+ * @return @a this
+ *
+ * The value of @a that is subtracted from the value of @a this.
+ */
template <intmax_t S, typename I> self_type &operator-=(Scalar<S, I, T> const &that);
/// @cond INTERNAL_DETAIL
@@ -373,6 +391,8 @@ protected:
Counter _n; ///< Number of scale units.
};
+/// @cond Scalar_INTERNAL
+// Avoid issues with doxygen matching externally defined methods.
template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::Scalar() : _n() {}
template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::Scalar(Counter n) : _n(n) {}
@@ -416,7 +436,7 @@ Scalar<N, C, T>::value() const {
return _n * SCALE;
}
-template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::operator C() const {
+template <intmax_t N, typename C, typename T> constexpr Scalar<N, C, T>::operator Counter() const {
return _n * SCALE;
}
@@ -436,7 +456,7 @@ Scalar<N, C, T>::operator=(self_type const &that) -> self_type & {
template <intmax_t N, typename C, typename T>
inline auto
-Scalar<N, C, T>::operator=(detail::scalar_round_up_t<N, C, T> v) -> self_type & {
+Scalar<N, C, T>::operator=(detail::scalar_round_up_t<N, C, T> v) -> self_type &{
_n = v._n;
return *this;
}
@@ -520,6 +540,8 @@ Scalar<N, C, T>::scale() {
return SCALE;
}
+/// @endcond Scalar_INTERNAL
+
// --- Functions ---
/** Prepare units @a n to be assigned to a @c Scalar, rounding up as needed.
@@ -629,6 +651,7 @@ Scalar<N, C, T>::operator+=(Scalar<S, I, T> const &that) -> self_type & {
return *this;
}
+/// @cond INTERNAL_DETAIL
template <intmax_t N, typename C, typename T>
template <typename I>
auto
@@ -659,18 +682,25 @@ Scalar<N, C, T>::operator+=(detail::scalar_round_down_t<N, C, T> v) -> self_type
return *this;
}
+/// @endcond
+
template <intmax_t N, typename C, intmax_t S, typename I, typename T>
auto
operator+(Scalar<N, C, T> lhs, Scalar<S, I, T> const &rhs) -> typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type {
return typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type(lhs) += rhs;
}
+/** Add a two scalars of the same type.
+ * @return A scalar of the same type holding the sum.
+ */
template <intmax_t N, typename C, typename T>
Scalar<N, C, T>
operator+(Scalar<N, C, T> const &lhs, Scalar<N, C, T> const &rhs) {
return Scalar<N, C, T>(lhs) += rhs;
}
+/// @cond INTERNAL_DETAIL
+// These handle adding a wrapper and a scalar.
template <intmax_t N, typename C, typename T, typename I>
Scalar<N, C, T>
operator+(detail::scalar_unit_round_up_t<I> lhs, Scalar<N, C, T> const &rhs) {
@@ -718,6 +748,7 @@ Scalar<N, C, T>
operator+(Scalar<N, C, T> const &lhs, detail::scalar_round_down_t<N, C, T> rhs) {
return Scalar<N, C, T>(lhs) += rhs._n;
}
+/// @endcond
template <intmax_t N, typename C, typename T>
auto
@@ -736,6 +767,8 @@ Scalar<N, C, T>::operator-=(Scalar<S, I, T> const &that) -> self_type & {
return *this;
}
+/// @cond INTERNAL_DETAIL
+
template <intmax_t N, typename C, typename T>
template <typename I>
auto
@@ -766,18 +799,25 @@ Scalar<N, C, T>::operator-=(detail::scalar_round_down_t<N, C, T> v) -> self_type
return *this;
}
+/// @endcond
+
template <intmax_t N, typename C, intmax_t S, typename I, typename T>
auto
operator-(Scalar<N, C, T> lhs, Scalar<S, I, T> const &rhs) -> typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type {
return typename std::common_type<Scalar<N, C, T>, Scalar<S, I, T>>::type(lhs) -= rhs;
}
+/** Subtract scalars.
+ * @return A scalar of the same type holding the difference @a lhs - @a rhs
+ */
template <intmax_t N, typename C, typename T>
Scalar<N, C, T>
operator-(Scalar<N, C, T> const &lhs, Scalar<N, C, T> const &rhs) {
return Scalar<N, C, T>(lhs) -= rhs;
}
+/// @cond INTERNAL_DETAIL
+// Handle subtraction for intermediate wrappers.
template <intmax_t N, typename C, typename T, typename I>
Scalar<N, C, T>
operator-(detail::scalar_unit_round_up_t<I> lhs, Scalar<N, C, T> const &rhs) {
@@ -825,6 +865,7 @@ Scalar<N, C, T>
operator-(Scalar<N, C, T> const &lhs, detail::scalar_round_down_t<N, C, T> rhs) {
return Scalar<N, C, T>(lhs) -= rhs._n;
}
+/// @endcond
template <intmax_t N, typename C, typename T>
auto
diff --git a/lib/swoc/include/swoc/TextView.h b/lib/swoc/include/swoc/TextView.h
index 8f9d1e04d..8608b108e 100644
--- a/lib/swoc/include/swoc/TextView.h
+++ b/lib/swoc/include/swoc/TextView.h
@@ -43,9 +43,10 @@ class TextView;
- self / parent type
- @c std::string
- literal string
- - C-string
+ - C-string pointer
- pointer and count
- begin/end style pointers.
+ - character containers that have the STL standard @c size and @c data methods.
*/
class TextView : public std::string_view {
using self_type = TextView; ///< Self reference type.
@@ -111,17 +112,21 @@ public:
*
* @param src A pointer to a C-string.
*
- * @internal This is a reference because it is otherwise ambiguous with the array constructor.
+ * The view does not include the terminating nul.
+ *
+ * @internal @a src a reference because it is otherwise ambiguous with the literal constructor.
*/
- TextView(char * & src) : super_type(src) {}
+ TextView(char * & src) : super_type(src, src ? strlen(src) : 0) {}
/** Construct from a const C-string.
*
* @param src Pointer to a const C-string.
*
- * @internal This is a reference because it is otherwise ambiguous with the array constructor.
+ * The view does not include the terminating nul.
+ *
+ * @internal @a src a reference because it is otherwise ambiguous with the literal constructor.
*/
- TextView(char const * & src) : super_type(src) {}
+ TextView(char const * & src) : super_type(src, src ? strlen(src) : 0) {}
/** Construct from nullptr.
This implicitly makes the length 0.
@@ -510,7 +515,7 @@ public:
* @return The prefix bounded by the first character satisfying @a pred, or all of @a this if none
* is found.
*
- * The prefix is removed and returned if a a character satisfying @a pred is found, otherwise
+ * The prefix is removed and returned if a character satisfying @a pred is found, otherwise
* all of @a this is removed and returned.
*
* @note The matching character is discarded if found.
@@ -962,6 +967,8 @@ double svtod(swoc::TextView text, swoc::TextView *parsed = nullptr);
// definition and the reference documentation is messed up. Sigh.
// === TextView Implementation ===
+/// @cond TextView_INTERNAL
+// Doxygen doesn't match these up well due to various type and template issues.
inline constexpr TextView::TextView(const char *ptr, size_t n) noexcept
: super_type(ptr, n == npos ? (ptr ? ::strlen(ptr) : 0) : n) {}
inline constexpr TextView::TextView(char const *first, char const *last) noexcept : super_type(first, last - first) {}
@@ -978,8 +985,8 @@ TextView::init_delimiter_set(std::string_view const &delimiters, std::bitset<256
set[static_cast<uint8_t>(c)] = true;
}
-inline TextView &
-TextView::clear() {
+inline auto
+TextView::clear() -> self_type & {
new (this) self_type();
return *this;
}
@@ -998,21 +1005,21 @@ inline constexpr TextView::operator bool() const noexcept {
return !this->empty();
}
-inline TextView &
-TextView::operator++() {
+inline auto
+TextView::operator++() -> self_type & {
this->remove_prefix(1);
return *this;
}
-inline TextView
-TextView::operator++(int) {
+inline auto
+TextView::operator++(int) -> self_type {
self_type zret{*this};
this->remove_prefix(1);
return zret;
}
-inline TextView &
-TextView::operator+=(size_t n) {
+inline auto
+TextView::operator+=(size_t n) -> self_type &{
this->remove_prefix(n);
return *this;
}
@@ -1023,42 +1030,42 @@ TextView::operator=(const char (&s)[N]) -> self_type & {
return *this = self_type{s, s[N - 1] ? N : N - 1};
}
-inline TextView &
-TextView::operator=(super_type const &that) {
+inline auto
+TextView::operator=(super_type const &that) -> self_type & {
this->super_type::operator=(that);
return *this;
}
-inline TextView &
-TextView::operator=(char *&s) {
+inline auto
+TextView::operator=(char *&s) -> self_type & {
this->super_type::operator=(s);
return *this;
}
-inline TextView &
-TextView::operator=(char const *&s) {
+inline auto
+TextView::operator=(char const *&s) -> self_type & {
this->super_type::operator=(s);
return *this;
}
-inline TextView &
-TextView::operator=(const std::string &s) {
+inline auto
+TextView::operator=(const std::string &s) -> self_type & {
this->super_type::operator=(s);
return *this;
}
-inline TextView &
-TextView::assign(char * & c_str) {
+inline auto
+TextView::assign(char * & c_str) -> self_type & {
return this->assign(c_str, strlen(c_str));
}
-inline TextView &
-TextView::assign(char const * & c_str) {
+inline auto
+TextView::assign(char const * & c_str) -> self_type & {
return this->assign(c_str, strlen(c_str));
}
-inline TextView &
-TextView::assign(const std::string &s) {
+inline auto
+TextView::assign(const std::string &s) -> self_type & {
*this = super_type(s);
return *this;
}
@@ -1081,8 +1088,8 @@ TextView::assign(char const (&s)[N]) noexcept -> self_type & {
return *this = self_type{s, s[N - 1] ? N : N - 1};
}
-inline constexpr TextView
-TextView::prefix(size_t n) const noexcept {
+inline constexpr auto
+TextView::prefix(size_t n) const noexcept -> self_type {
return {this->data(), std::min(n, this->size())};
}
@@ -1091,8 +1098,8 @@ TextView::prefix(int n) const noexcept {
return {this->data(), std::min<size_t>(n, this->size())};
}
-inline TextView
-TextView::prefix_at(char c) const {
+inline auto
+TextView::prefix_at(char c) const -> self_type {
self_type zret; // default to empty return.
if (auto n = this->find(c); n != npos) {
zret.assign(this->data(), n);
@@ -1110,8 +1117,8 @@ TextView::prefix_at(std::string_view const &delimiters) const {
}
template <typename F>
-TextView::self_type
-TextView::prefix_if(F const &pred) const {
+auto
+TextView::prefix_if(F const &pred) const -> self_type {
self_type zret; // default to empty return.
if (auto n = this->find_if(pred); n != npos) {
zret.assign(this->data(), n);
@@ -1133,8 +1140,8 @@ TextView::remove_prefix_at(char c) {
return *this;
}
-inline TextView &
-TextView::remove_prefix_at(std::string_view const &delimiters) {
+inline auto
+TextView::remove_prefix_at(std::string_view const &delimiters) -> self_type & {
if (auto n = this->find_first_of(delimiters); n != npos) {
this->super_type::remove_prefix(n + 1);
}
@@ -1142,8 +1149,8 @@ TextView::remove_prefix_at(std::string_view const &delimiters) {
}
template <typename F>
-TextView::self_type &
-TextView::remove_prefix_if(F const &pred) {
+auto
+TextView::remove_prefix_if(F const &pred) -> self_type & {
if (auto n = this->find_if(pred); n != npos) {
this->super_type::remove_prefix(n + 1);
}
@@ -1200,8 +1207,8 @@ TextView::take_prefix_at(std::string_view const &delimiters) {
}
template <typename F>
-TextView::self_type
-TextView::take_prefix_if(F const &pred) {
+auto
+TextView::take_prefix_if(F const &pred) -> self_type {
return this->take_prefix(this->find_if(pred));
}
@@ -1237,8 +1244,8 @@ TextView::suffix_at(std::string_view const &delimiters) const {
}
template <typename F>
-TextView::self_type
-TextView::suffix_if(F const &pred) const {
+auto
+TextView::suffix_if(F const &pred) const -> self_type {
self_type zret;
if (auto n = this->rfind_if(pred); n != npos) {
++n;
@@ -1334,7 +1341,7 @@ TextView::take_suffix_at(std::string_view const &delimiters) {
template <typename F>
TextView::self_type
-TextView::take_suffix_if(F const &pred) {
+TextView::take_suffix_if(F const &pred){
return this->take_suffix_at(this->rfind_if(pred));
}
@@ -1585,6 +1592,7 @@ TextView::clip_suffix_of(F const &pred) {
this->remove_suffix(idx);
return token;
}
+/// @endcond TextView_INTERNAL
// Provide an instantiation for @c std::ostream as it's likely this is the only one ever used.
extern template std::ostream &TextView::stream_write(std::ostream &, const TextView &) const;
@@ -1753,7 +1761,7 @@ transform_view_of(X const &xf, V const &src) {
* @tparam V The source type.
*
* This is a transform that returns the input unmodified. This is convenient when a transform is
- * required in general but not in in all cases.
+ * required in general but not in all cases.
*/
template <typename V> class TransformView<void, V> {
using self_type = TransformView; ///< Self reference type.
@@ -1939,6 +1947,11 @@ template <typename X, typename V> struct iterator_traits<swoc::TransformView<X,
using difference_type = ssize_t;
using iterator_category = forward_iterator_tag;
};
+
+template <> struct hash<swoc::TextView> {
+ static constexpr hash<string_view> super_hash{};
+ size_t operator()(swoc::TextView const& s) const { return super_hash(s); }
+};
/// @endcond
} // namespace std
diff --git a/lib/swoc/include/swoc/Vectray.h b/lib/swoc/include/swoc/Vectray.h
index 42f7a3763..a4c7246a0 100644
--- a/lib/swoc/include/swoc/Vectray.h
+++ b/lib/swoc/include/swoc/Vectray.h
@@ -36,19 +36,19 @@ namespace swoc { inline namespace SWOC_VERSION_NS {
template < typename T, size_t N, class A = std::allocator<T> >
class Vectray {
using self_type = Vectray; ///< Self reference type.
- using vector_type = std::vector<T, A>;
+ using vector_type = std::vector<T, A>; ///< Internal dynamic storage type.
public: // STL compliance types.
- using value_type = T;
- using reference = std::remove_reference<T>&;
- using const_reference = std::remove_reference<T> const&;
- using pointer = std::remove_reference<T>*;
- using const_pointer = std::remove_reference<T> const*;
- using allocator_type = A;
- using size_type = typename vector_type::size_type;
- using difference_type = typename vector_type::difference_type;
- using iterator = typename swoc::MemSpan<T>::iterator;
- using const_iterator = typename swoc::MemSpan<const T>::iterator;
+ using value_type = T; ///< Element type for container.
+ using reference = std::remove_reference<T>&; ///< Reference to element.
+ using const_reference = std::remove_reference<T> const&; ///< Reference to constant element.
+ using pointer = std::remove_reference<T>*; ///< Pointer to element.
+ using const_pointer = std::remove_reference<T> const*; ///< Pointer to constant element.
+ using allocator_type = A; ///< Dynamic storage allocator.
+ using size_type = typename vector_type::size_type; ///< Type for element count.
+ using difference_type = typename vector_type::difference_type; ///< Iterator difference.
+ using iterator = typename swoc::MemSpan<T>::iterator; ///< Element iteration.
+ using const_iterator = typename swoc::MemSpan<const T>::iterator; ///< Constant element iteration.
// Need to add reverse iterators - @c reverse_iterator and @c const_reverse_iterator
/// Internal (fixed) storage.
@@ -79,8 +79,9 @@ public: // STL compliance types.
using DynamicStore = vector_type; ///< Dynamic (heap) storage.
- /// Generic form for referencing stored objects.
+ /// Element access.
using span = swoc::MemSpan<T>;
+ /// Constant element access.
using const_span = swoc::MemSpan<T const>;
public:
@@ -100,6 +101,7 @@ public:
*/
explicit Vectray(size_type n, allocator_type const& alloc = allocator_type{});
+ /// Move constructor for difference static sized instance.
template < size_t M > Vectray(Vectray<T, M, A> && that);
/// Move constructor.
@@ -157,14 +159,14 @@ public:
}
/** Append an element by copy.
*
- * @param src Element to add.
+ * @param t Element to add.
* @return @a this.
*/
self_type& push_back(T const& t);
/** Append an element by move.
*
- * @param src Element to add.
+ * @param t Element to add.
* @return @a this.
*/
self_type& push_back(T && t);
@@ -175,7 +177,7 @@ public:
* @param args Constructor arguments.
* @return @a this
*/
- template < typename ... Args> self_type& emplace_back(Args && ... args);
+ template < typename ... Args> self_type & emplace_back(Args && ... args);
/** Remove an element from the end of the current elements.
*
@@ -261,7 +263,7 @@ template <typename T, size_t N, class A> Vectray<T, N, A>::FixedStore::~FixedSto
template<typename T, size_t N, class A>
MemSpan<T> Vectray<T, N, A>::FixedStore::span() {
- return MemSpan(_raw).template rebind<T>();
+ return MemSpan<std::byte>(_raw).template rebind<T>();
}
template<typename T, size_t N, class A>
@@ -322,7 +324,7 @@ auto Vectray<T,N,A>::push_back(T && t) -> self_type& {
template<typename T, size_t N, class A>
template<typename... Args>
-auto Vectray<T, N, A>::emplace_back(Args && ... args) -> self_type& {
+typename Vectray<T,N,A>::self_type & Vectray<T, N, A>::emplace_back(Args && ... args) {
if (_store.index() == FIXED) {
auto& fs{std::get<FIXED>(_store)};
if (fs._count < N) {
diff --git a/lib/swoc/include/swoc/bwf_base.h b/lib/swoc/include/swoc/bwf_base.h
index a13e18f21..5c122b430 100644
--- a/lib/swoc/include/swoc/bwf_base.h
+++ b/lib/swoc/include/swoc/bwf_base.h
@@ -118,7 +118,7 @@ protected:
static constexpr uint8_t UPPER_TYPE_CHAR = 0x20; ///< Upper case flag.
static constexpr uint8_t NUMERIC_TYPE_CHAR = 0x40; ///< Numeric output.
static constexpr uint8_t SIGN_CHAR = 0x80; ///< Is sign character.
- } _prop;
+ } _prop; ///< Character property map.
};
/** Format string support.
@@ -172,8 +172,15 @@ public:
struct FormatExtractor {
const std::vector<Spec> &_fmt; ///< Parsed format string.
int _idx = 0; ///< Element index.
+ /// @return @c true if more format string, @c false if none.
explicit operator bool() const;
+ /** Extract next formatting elements.
+ *
+ * @param literal_v [out] The next literal.
+ * @param spec [out] The next format specifier.
+ * @return @c true if @a spec was filled out, @c false if no specifier was found.
+ */
bool operator()(std::string_view &literal_v, Spec &spec);
};
@@ -278,8 +285,9 @@ 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; ///< Mapping of name -> generator
+ Map _map; ///< Defined generators.
MemArena _arena{1024}; ///< Local name storage.
};
@@ -341,6 +349,7 @@ public:
using super_type::super_type; // inherit @c super_type constructors.
+ /// Specialized binding for names in an instance of @c ContextNames
class Binding : public NameBinding {
public:
/** Override of virtual method to provide an implementation.
@@ -358,12 +367,17 @@ public:
}
protected:
+ /** Constructor.
+ *
+ * @param names Names to define for the binding.
+ * @param ctx Binding context.
+ */
Binding(ContextNames const &names, context_type &ctx) : _ctx(ctx), _names(names) {}
context_type &_ctx; ///< Context for generators.
ContextNames const &_names; ///< Base set of names.
- friend ContextNames;
+ friend class ContextNames;
};
/** Assign the external generator @a bg to @a name.
@@ -900,34 +914,38 @@ BufferWriter::aux_span() {
// ---- Formatting for specific types.
-// Must be first because it is used by other formatters, and is not inline.
+/** Output a @c string_view.
+ *
+ * @param w Output
+ * @param spec Format specifier
+ * @param sv View to format.
+ * @return @a w
+ *
+ * @internal Must be first because it is used by other formatters, and is not inline.
+ */
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv);
-// Pointers that are not specialized.
-inline BufferWriter &
-bwformat(BufferWriter &w, bwf::Spec const &spec, const void *ptr) {
- using namespace swoc::literals;
- bwf::Spec ptr_spec{spec};
- ptr_spec._radix_lead_p = true;
-
- if (ptr == nullptr) {
- if (spec._type == 's' || spec._type == 'S') {
- ptr_spec._type = bwf::Spec::DEFAULT_TYPE;
- ptr_spec._ext = ""_sv; // clear any extension.
- return bwformat(w, spec, spec._type == 's' ? "null"_sv : "NULL"_sv);
- } else if (spec._type == bwf::Spec::DEFAULT_TYPE) {
- return w; // print nothing if there is no format character override.
- }
- }
-
- if (ptr_spec._type == bwf::Spec::DEFAULT_TYPE || ptr_spec._type == 'p') {
- ptr_spec._type = 'x'; // if default or 'p;, switch to lower hex.
- } else if (ptr_spec._type == 'P') {
- ptr_spec._type = 'X'; // P means upper hex, overriding other specializations.
- }
- return bwf::Format_Integer(w, ptr_spec, reinterpret_cast<intptr_t>(ptr), false);
-}
+/** Format non-specialized pointers.
+ *
+ * @param w Output
+ * @param spec Format specifier.
+ * @param ptr Pointer to format.
+ * @return @a w
+ *
+ * Non-specialized pointers are formatted simply as pointers, rather than the pointed to data.
+ */
+BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, const void *ptr);
+/** Format a generic (void) memory span.
+ *
+ * @param w Output
+ * @param spec Format specifier.
+ * @param span Span to format.
+ * @return @a w
+ *
+ * The format is by default "N:ptr" where N is the size and ptr is a hex formatter pointer. If the
+ * format is "x" or "X" the span content is dumped as contiguous hex.
+ */
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, MemSpan<void> const &span);
template <typename T>
@@ -1194,6 +1212,13 @@ As_Hex(T const &t) {
} // namespace bwf
+/** Format a hex dump.
+ *
+ * @param w The output.
+ * @param spec Format specifier.
+ * @param hex Hex dump wrapper.
+ * @return @a w
+ */
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::HexDump const &hex);
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/lib/swoc/include/swoc/bwf_ex.h b/lib/swoc/include/swoc/bwf_ex.h
index 318f3ee59..c232591bd 100644
--- a/lib/swoc/include/swoc/bwf_ex.h
+++ b/lib/swoc/include/swoc/bwf_ex.h
@@ -32,8 +32,9 @@ struct Pattern {
* is type 'd' then just the numeric value is printed.
*/
struct Errno {
- int _e;
+ int _e; ///< Errno value.
+ /// Construct wrapper, default to current @c errno
explicit Errno(int e = errno) : _e(e) {}
};
@@ -42,12 +43,19 @@ struct Errno {
* provided a format like "2017 Jun 29 14:11:29" is used.
*/
struct Date {
+ /// Default format
static constexpr std::string_view DEFAULT_FORMAT{"%Y %b %d %H:%M:%S"_sv};
- time_t _epoch;
- std::string_view _fmt;
+ time_t _epoch; ///< The time.
+ std::string_view _fmt; ///< Data format.
+ /** Constructor.
+ *
+ * @param t The timestamp.
+ * @param fmt Timestamp format.
+ */
Date(time_t t, std::string_view fmt = DEFAULT_FORMAT) : _epoch(t), _fmt(fmt) {}
+ /// Default construct using current time with optional format.
Date(std::string_view fmt = DEFAULT_FORMAT);
};
@@ -200,12 +208,51 @@ Optional(TextView fmt, ARG &&arg) {
}
} // namespace bwf
+/** Repeatedly output a pattern.
+ *
+ * @param w Output.
+ * @param spec Format specifier.
+ * @param pattern Output patterning.
+ * @return @a w
+ *
+ * The @a pattern contains the count and text to output.
+ */
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Pattern const &pattern);
+/** Format an integer as an @c errno value.
+ *
+ * @param w Output.
+ * @param spec Format specifier.
+ * @param e Error code.
+ * @return @a w
+ */
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Errno const &e);
+/** Format a timestamp wrapped in a @c Date.
+ *
+ * @param w Output.
+ * @param spec Format specifier.
+ * @param date Timestamp.
+ * @return @a w
+ */
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Date const &date);
+/** Output a nested formatted string.
+ *
+ * @tparam Args Argument pack for @a subtext.
+ * @param w Output
+ * @param subtext Format string and arguments.
+ * @return @a w
+ *
+ * This supports a nested format string and arguments inside another format string. This is most often useful
+ * if one of the formats is fixed or pre-compiled.
+ *
+ * @code
+ * bwformat(w, "Line {} offset {} with data {}.", line_no, line_off, bwf::SubText("alpha {} bravo {}", alpha, bravo"));
+ * @endcode
+ *
+ * @see bwf::Subtext
+ */
template <typename... Args>
BufferWriter &
bwformat(BufferWriter &w, bwf::Spec const &, bwf::SubText<Args...> const &subtext) {
diff --git a/lib/swoc/include/swoc/swoc_file.h b/lib/swoc/include/swoc/swoc_file.h
index 8e3c68ef0..33d13a9c8 100644
--- a/lib/swoc/include/swoc/swoc_file.h
+++ b/lib/swoc/include/swoc/swoc_file.h
@@ -22,9 +22,10 @@ namespace file {
/** Utility class for file system paths.
*/
class path {
- using self_type = path;
+ using self_type = path; ///< Self reference type.
public:
+ /// Default path separator.
static constexpr char SEPARATOR = '/';
/// Default construct empty path.
@@ -65,6 +66,14 @@ public:
*/
self_type &operator/=(const self_type &that);
+ /** Append or replace path with @a that.
+ *
+ * If @a that is absolute, it replaces @a this. Otherwise @a that is appended with exactly one
+ * separator.
+ *
+ * @param that Filesystem path.
+ * @return @a this
+ */
self_type &operator/=(std::string_view that);
/// Check if the path is empty.
@@ -76,6 +85,7 @@ public:
/// Check if the path is not absolute.
bool is_relative() const;
+ /// Path of the parent.
self_type parent_path() const;
/// Access the path explicitly.
@@ -154,8 +164,11 @@ bool is_readable(const path &s);
*/
path absolute(path const &src, std::error_code &ec);
+/// @return The modified time for @a fs.
std::chrono::system_clock::time_point modify_time(file_status const &fs);
+/// @return The access time for @a fs.
std::chrono::system_clock::time_point access_time(file_status const &fs);
+/// @return The status change time for @a fs.
std::chrono::system_clock::time_point status_time(file_status const &fs);
/** Load the file at @a p into a @c std::string.
@@ -215,35 +228,55 @@ path::operator/=(const self_type &that) {
return *this /= std::string_view(that._path);
}
+/** Compare two paths.
+ *
+ * @return @c true if @a lhs is identical to @a rhs.
+ */
inline bool
operator==(path const &lhs, path const &rhs) {
return lhs.view() == rhs.view();
}
+/** Compare two paths.
+ *
+ * @return @c true if @a lhs is not identical to @a rhs.
+ */
inline bool
operator!=(path const &lhs, path const &rhs) {
return lhs.view() != rhs.view();
}
/** Combine two strings as file paths.
-
- @return A @c path with the combined path.
-*/
+ *
+ * @return A @c path with the combined path.
+ */
inline path
operator/(const path &lhs, const path &rhs) {
return path(lhs) /= rhs;
}
+/** Combine two strings as file paths.
+ *
+ * @return A @c path with the combined path.
+ */
inline path
operator/(path &&lhs, const path &rhs) {
return path(std::move(lhs)) /= rhs;
}
+/** Combine two strings as file paths.
+ *
+ * @return A @c path with the combined path.
+ */
inline path
operator/(const path &lhs, std::string_view rhs) {
return path(lhs) /= rhs;
}
+/** Combine two strings as file paths.
+ *
+ * @return A @c path with the combined path.
+ */
inline path
operator/(path &&lhs, std::string_view rhs) {
return path(std::move(lhs)) /= rhs;
diff --git a/lib/swoc/include/swoc/swoc_ip.h b/lib/swoc/include/swoc/swoc_ip.h
index 2132c73c0..4f76450dd 100644
--- a/lib/swoc/include/swoc/swoc_ip.h
+++ b/lib/swoc/include/swoc/swoc_ip.h
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
-// SPDX-License-Identifier: Apache-2.0
// Copyright Network Geographics 2014
/** @file
IP address and network related classes.
@@ -334,11 +333,8 @@ protected:
using bytes = std::array<uint8_t, 4>;
friend bool operator==(self_type const &, self_type const &);
-
friend bool operator!=(self_type const &, self_type const &);
-
friend bool operator<(self_type const &, self_type const &);
-
friend bool operator<=(self_type const &, self_type const &);
in_addr_t _addr = INADDR_ANY; ///< Address in host order.
@@ -480,21 +476,21 @@ public:
/** Bitwise AND.
*
- * @param that Source address.
+ * @param that Source mask.
* @return @a this.
*
* The bits in @a this are set to the bitwise AND of the corresponding bits in @a this and @a that.
*/
- self_type &operator&=(IPMask const &mask);
+ self_type &operator&=(IPMask const &that);
/** Bitwise OR.
*
- * @param that Source address.
+ * @param that Source mask.
* @return @a this.
*
* The bits in @a this are set to the bitwise OR of the corresponding bits in @a this and @a that.
*/
- self_type &operator|=(IPMask const &mask);
+ self_type &operator|=(IPMask const &that);
/** Convert between network and host ordering.
*
@@ -986,6 +982,7 @@ protected:
bool is_valid(IP4Addr mask) const;
};
+/// Inclusive range of IPv6 addresses.
class IP6Range : public DiscreteRange<IP6Addr> {
using self_type = IP6Range;
using super_type = DiscreteRange<IP6Addr>;
@@ -1118,6 +1115,10 @@ protected:
bool is_valid(IPMask const &mask);
};
+/** 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.
+ */
class IPRange {
using self_type = IPRange;
@@ -1180,17 +1181,14 @@ public:
/// @return The maximum address in the range.
IPAddr max() const;
+ /// @return @c true if there are no addresses in the range.
bool empty() const;
- IP4Range const &
- ip4() const {
- return _range._ip4;
- }
+ /// @return The IPv4 range.
+ IP4Range const & ip4() const { return _range._ip4; }
- IP6Range const &
- ip6() const {
- return _range._ip6;
- }
+ /// @return The IPv6 range.
+ IP6Range const & ip6() const { return _range._ip6; }
/** Compute the mask for @a this as a network.
*
@@ -1289,11 +1287,11 @@ public:
protected:
union {
- std::monostate _nil;
- IP4Range::NetSource _ip4;
- IP6Range::NetSource _ip6;
+ std::monostate _nil; ///< Default value, no addresses.
+ IP4Range::NetSource _ip4; ///< IPv4 addresses.
+ IP6Range::NetSource _ip6; ///< IPv6 addresses.
};
- sa_family_t _family = AF_UNSPEC;
+ sa_family_t _family = AF_UNSPEC; ///< Mark for union content.
};
/// An IPv4 network.
@@ -1347,11 +1345,7 @@ public:
self_type &assign(IP4Addr const &addr, IPMask const &mask);
/// Reset network to invalid state.
- self_type &
- clear() {
- _mask.clear();
- return *this;
- }
+ self_type & clear() { _mask.clear(); return *this; }
/// Equality.
bool operator==(self_type const &that) const;
@@ -1364,6 +1358,7 @@ protected:
IPMask _mask; ///< Network mask.
};
+/// IPv6 network.
class IP6Net {
using self_type = IP6Net; ///< Self reference type.
public:
@@ -2148,38 +2143,47 @@ IPAddr::invalidate() {
}
// Associated operators.
+
+/// Equality.
bool operator==(IPAddr const &lhs, sockaddr const *rhs);
+/// Equality.
inline bool
operator==(sockaddr const *lhs, IPAddr const &rhs) {
return rhs == lhs;
}
+/// Inequality.
inline bool
operator!=(IPAddr const &lhs, sockaddr const *rhs) {
return !(lhs == rhs);
}
+/// Inequality.
inline bool
operator!=(sockaddr const *lhs, IPAddr const &rhs) {
return !(rhs == lhs);
}
+/// Equality.
inline bool
operator==(IPAddr const &lhs, IPEndpoint const &rhs) {
return lhs == &rhs.sa;
}
+/// Equality.
inline bool
operator==(IPEndpoint const &lhs, IPAddr const &rhs) {
return &lhs.sa == rhs;
}
+/// Inequality.
inline bool
operator!=(IPAddr const &lhs, IPEndpoint const &rhs) {
return !(lhs == &rhs.sa);
}
+/// Inequality.
inline bool
operator!=(IPEndpoint const &lhs, IPAddr const &rhs) {
return !(rhs == &lhs.sa);
@@ -2301,7 +2305,7 @@ IPEndpoint::host_order_port(sockaddr const *sa) {
inline constexpr IP4Addr::IP4Addr(in_addr_t addr) : _addr(addr) {}
-inline IP4Addr::IP4Addr(std::string_view const &text) {
+inline IP4Addr::IP4Addr(string_view const &text) {
if (!this->load(text)) {
_addr = INADDR_ANY;
}
@@ -2361,31 +2365,37 @@ IP4Addr::operator=(in_addr_t ip) -> self_type & {
return *this;
}
+/// Equality.
inline bool
operator==(IP4Addr const &lhs, IP4Addr const &rhs) {
return lhs._addr == rhs._addr;
}
+/// @return @c true if @a lhs is equal to @a rhs.
inline bool
operator!=(IP4Addr const &lhs, IP4Addr const &rhs) {
return lhs._addr != rhs._addr;
}
+/// @return @c true if @a lhs is less than @a rhs (host order).
inline bool
operator<(IP4Addr const &lhs, IP4Addr const &rhs) {
return lhs._addr < rhs._addr;
}
+/// @return @c true if @a lhs is less than or equal to@a rhs (host order).
inline bool
operator<=(IP4Addr const &lhs, IP4Addr const &rhs) {
return lhs._addr <= rhs._addr;
}
+/// @return @c true if @a lhs is greater than @a rhs (host order).
inline bool
operator>(IP4Addr const &lhs, IP4Addr const &rhs) {
return rhs < lhs;
}
+/// @return @c true if @a lhs is greater than or equal to @a rhs (host order).
inline bool
operator>=(IP4Addr const &lhs, IP4Addr const &rhs) {
return rhs <= lhs;
@@ -2434,7 +2444,7 @@ inline IP6Addr::IP6Addr(in6_addr const &addr) {
*this = addr;
}
-inline IP6Addr::IP6Addr(std::string_view const &text) {
+inline IP6Addr::IP6Addr(string_view const &text) {
if (!this->load(text)) {
this->clear();
}
@@ -2527,33 +2537,39 @@ IP6Addr::reorder(unsigned char dst[WORD_SIZE], unsigned char const src[WORD_SIZE
}
}
+/// @return @c true if @a lhs is equal to @a rhs.
inline bool
operator==(IP6Addr const &lhs, IP6Addr const &rhs) {
return lhs._addr._store[0] == rhs._addr._store[0] && lhs._addr._store[1] == rhs._addr._store[1];
}
+/// @return @c true if @a lhs is not equal to @a rhs.
inline bool
operator!=(IP6Addr const &lhs, IP6Addr const &rhs) {
return lhs._addr._store[0] != rhs._addr._store[0] || lhs._addr._store[1] != rhs._addr._store[1];
}
+/// @return @c true if @a lhs is less than @a rhs.
inline bool
operator<(IP6Addr const &lhs, IP6Addr const &rhs) {
return lhs._addr._store[0] < rhs._addr._store[0] ||
(lhs._addr._store[0] == rhs._addr._store[0] && lhs._addr._store[1] < rhs._addr._store[1]);
}
+/// @return @c true if @a lhs is greater than @a rhs.
inline bool
operator>(IP6Addr const &lhs, IP6Addr const &rhs) {
return rhs < lhs;
}
+/// @return @c true if @a lhs is less than or equal to @a rhs.
inline bool
operator<=(IP6Addr const &lhs, IP6Addr const &rhs) {
return lhs._addr._store[0] < rhs._addr._store[0] ||
(lhs._addr._store[0] == rhs._addr._store[0] && lhs._addr._store[1] <= rhs._addr._store[1]);
}
+/// @return @c true if @a lhs is greater than or equal to @a rhs.
inline bool
operator>=(IP6Addr const &lhs, IP6Addr const &rhs) {
return rhs <= lhs;
@@ -3349,27 +3365,27 @@ get(swoc::IPNet const &net) {
}} // namespace swoc::SWOC_VERSION_NS
namespace std {
+/// Standard hash support for @a IP4Addr.
template <> struct hash<swoc::IP4Addr> {
- uint32_t operator()(swoc::IP4Addr const &addr) const {
+ size_t operator()(swoc::IP4Addr const &addr) const {
return addr.network_order();
}
};
+/// Standard hash support for @a IP6Addr.
template <> struct hash<swoc::IP6Addr> {
- uint32_t operator()(swoc::IP6Addr const &addr) const {
+ size_t operator()(swoc::IP6Addr const &addr) const {
// XOR the 64 chunks then XOR that down to 32 bits.
auto words = addr.as_span<uint64_t>();
- union {
- uint64_t w;
- uint32_t n[2];
- } x{words[0] ^ words[1]};
- return x.n[0] ^ x.n[1];
+ return words[0] ^ words[1];
}
};
+/// Standard hash support for @a IPAddr.
template <> struct hash<swoc::IPAddr> {
- uint32_t operator()(swoc::IPAddr const &addr) const {
+ size_t operator()(swoc::IPAddr const &addr) const {
return addr.is_ip4() ? hash<swoc::IP4Addr>()(addr.ip4()) : addr.is_ip6() ? hash<swoc::IP6Addr>()(addr.ip6()) : 0;
}
};
+
} // namespace std
diff --git a/lib/swoc/include/swoc/swoc_meta.h b/lib/swoc/include/swoc/swoc_meta.h
index 0ed41b73b..959f68d35 100644
--- a/lib/swoc/include/swoc/swoc_meta.h
+++ b/lib/swoc/include/swoc/swoc_meta.h
@@ -65,18 +65,18 @@ namespace swoc { inline namespace SWOC_VERSION_NS { namespace meta {
template <unsigned N> struct CaseTag : /** @cond DOXYGEN_FAIL */ public CaseTag<N - 1> /** @endcond */ {
constexpr CaseTag() {}
- static constexpr unsigned value = N;
+ static constexpr unsigned value = N; ///< Case tag value.
};
-/// Anchor the hierarchy.
+/// Case hierarchy anchor.
template <> struct CaseTag<0> {
constexpr CaseTag() {}
- static constexpr unsigned value = 0;
+ static constexpr unsigned value = 0; ///< Case tag value.
};
-/** This is the final case - it forces the super class hierarchy.
- * After defining the cases using the indexed case arguments, this is used to to perform the call.
+/** This is the final case - it forces the class hierarchy.
+ * After defining the cases using the indexed case arguments, this is used to perform the call.
* To increase the hierarchy depth, change the template argument to a larger number.
*/
static constexpr CaseTag<9> CaseArg{};
diff --git a/lib/swoc/include/swoc/swoc_version.h b/lib/swoc/include/swoc/swoc_version.h
index c39d78539..f64636427 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_3_8
+#define SWOC_VERSION_NS _1_3_11
#endif
namespace swoc { inline namespace SWOC_VERSION_NS {
static constexpr unsigned MAJOR_VERSION = 1;
static constexpr unsigned MINOR_VERSION = 3;
-static constexpr unsigned POINT_VERSION = 8;
+static constexpr unsigned POINT_VERSION = 11;
}} // namespace swoc::SWOC_VERSION_NS
diff --git a/lib/swoc/src/Errata.cc b/lib/swoc/src/Errata.cc
index 08f1e5536..d7fa508b3 100644
--- a/lib/swoc/src/Errata.cc
+++ b/lib/swoc/src/Errata.cc
@@ -27,10 +27,6 @@ std::vector<Errata::Sink::Handle> Sink_List;
std::string_view Errata::DEFAULT_GLUE{"\n", 1};
-/** This is the implementation class for Errata.
-
- It holds the actual messages and is treated as a passive data object with nice constructors.
-*/
string_view
Errata::Data::localize(string_view src) {
auto span = _arena.alloc(src.size());
@@ -45,7 +41,7 @@ Errata::Severity Errata::DEFAULT_SEVERITY(2);
Errata::Severity Errata::FAILURE_SEVERITY(2);
Errata::Severity Errata::FILTER_SEVERITY(0);
-// Provide a somewhat reasonable set of default severities and names
+/// Default set of severity names.
std::array<swoc::TextView, 4> Severity_Names{{"Info", "Warning", "Error"}};
swoc::MemSpan<TextView const> Errata::SEVERITY_NAMES{Severity_Names.data(), Severity_Names.size()};
diff --git a/lib/swoc/src/bw_format.cc b/lib/swoc/src/bw_format.cc
index f22a522f8..20c43ecb9 100644
--- a/lib/swoc/src/bw_format.cc
+++ b/lib/swoc/src/bw_format.cc
@@ -648,6 +648,30 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, std::string_view sv) {
return w;
}
+BufferWriter &
+bwformat(BufferWriter &w, bwf::Spec const &spec, const void *ptr) {
+ using namespace swoc::literals;
+ bwf::Spec ptr_spec{spec};
+ ptr_spec._radix_lead_p = true;
+
+ if (ptr == nullptr) {
+ if (spec._type == 's' || spec._type == 'S') {
+ ptr_spec._type = bwf::Spec::DEFAULT_TYPE;
+ ptr_spec._ext = ""_sv; // clear any extension.
+ return bwformat(w, spec, spec._type == 's' ? "null"_sv : "NULL"_sv);
+ } else if (spec._type == bwf::Spec::DEFAULT_TYPE) {
+ return w; // print nothing if there is no format character override.
+ }
+ }
+
+ if (ptr_spec._type == bwf::Spec::DEFAULT_TYPE || ptr_spec._type == 'p') {
+ ptr_spec._type = 'x'; // if default or 'p;, switch to lower hex.
+ } else if (ptr_spec._type == 'P') {
+ ptr_spec._type = 'X'; // P means upper hex, overriding other specializations.
+ }
+ return bwf::Format_Integer(w, ptr_spec, reinterpret_cast<intptr_t>(ptr), false);
+}
+
BufferWriter &
bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::HexDump const &hex) {
char fmt_type = spec._type;
@@ -672,7 +696,7 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::HexDump const &hex) {
BufferWriter &
bwformat(BufferWriter &w, bwf::Spec const &spec, MemSpan<void> const &span) {
if ('x' == spec._type || 'X' == spec._type) {
- const char *digits = 'X' == spec._type ? bwf::UPPER_DIGITS : bwf::LOWER_DIGITS;
+ const char *digits = ('X' == spec._type) ? bwf::UPPER_DIGITS : bwf::LOWER_DIGITS;
size_t block = spec._prec > 0 ? spec._prec : span.size();
TextView view{span.view()};
bool space_p = false;