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 &note_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;