diff --git a/lib/swoc/CMakeLists.txt b/lib/swoc/CMakeLists.txt index 33a0ce7f57f..06df0479e09 100644 --- a/lib/swoc/CMakeLists.txt +++ b/lib/swoc/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.11) project(Lib-SWOC CXX) -set(LIBSWOC_VERSION "1.5.3") +set(LIBSWOC_VERSION "1.5.5") set(CMAKE_CXX_STANDARD 17) cmake_policy(SET CMP0087 NEW) # override "lib64" to be "lib" unless the user explicitly sets it. diff --git a/lib/swoc/Makefile.am b/lib/swoc/Makefile.am index ad56edd7928..118e09c8351 100644 --- a/lib/swoc/Makefile.am +++ b/lib/swoc/Makefile.am @@ -22,7 +22,7 @@ library_includedir=$(includedir)/swoc AM_CPPFLAGS += @SWOC_INCLUDES@ -libtsswoc_la_LDFLAGS = @AM_LDFLAGS@ -no-undefined -release 1.5.3 +libtsswoc_la_LDFLAGS = @AM_LDFLAGS@ -no-undefined -release 1.5.5 libtsswoc_la_SOURCES = \ src/ArenaWriter.cc src/bw_format.cc src/bw_ip_format.cc src/Errata.cc src/MemArena.cc src/RBTree.cc src/swoc_file.cc src/swoc_ip.cc src/TextView.cc src/string_view_util.cc diff --git a/lib/swoc/include/swoc/BufferWriter.h b/lib/swoc/include/swoc/BufferWriter.h index 4de2d97074b..85e17f144eb 100644 --- a/lib/swoc/include/swoc/BufferWriter.h +++ b/lib/swoc/include/swoc/BufferWriter.h @@ -264,6 +264,28 @@ class BufferWriter { */ template BufferWriter &print_n(Binding const &names, TextView const &fmt); + /** Write formattted data. + * + * @tparam T Data type. + * @param spec Format specifier. + * @param t Instance to print. + * @return @a this + * + * Essentially this forwards @a t to @c bwformat. + */ + template BufferWriter & format(bwf::Spec const& spec, T && t); + + /** Write formattted data. + * + * @tparam T Data type. + * @param spec Format specifier. + * @param t Instance to print. + * @return @a this + * + * Essentially this forwards @a t to @c bwformat. + */ + template BufferWriter & format(bwf::Spec const& spec, T const& t); + /** IO stream operator. * * @param stream Output stream. diff --git a/lib/swoc/include/swoc/bwf_base.h b/lib/swoc/include/swoc/bwf_base.h index c36206afae4..75e7a7de3e5 100644 --- a/lib/swoc/include/swoc/bwf_base.h +++ b/lib/swoc/include/swoc/bwf_base.h @@ -1318,4 +1318,17 @@ BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::HexDump cons inline BufferWriter &bwformat(BufferWriter &w, bwf::Spec const& spec, BufferWriter const& ww) { return bwformat(w, spec, TextView(ww)); } + +template +BufferWriter & +BufferWriter::format(bwf::Spec const &spec, T const &t) { + return bwformat(*this, spec, t); +} + +template +BufferWriter & +BufferWriter::format(bwf::Spec const &spec, T && t) { + return bwformat(*this, spec, t); +} + }} // namespace swoc::SWOC_VERSION_NS diff --git a/lib/swoc/include/swoc/bwf_ex.h b/lib/swoc/include/swoc/bwf_ex.h index c232591bd25..47fc0b48430 100644 --- a/lib/swoc/include/swoc/bwf_ex.h +++ b/lib/swoc/include/swoc/bwf_ex.h @@ -206,6 +206,23 @@ SubText Optional(TextView fmt, ARG &&arg) { return detail::Optional(meta::CaseArg, fmt, std::forward(arg)); } + +/** Convert from ASCII hexadecimal to raw bytes. + * + * E.g. if the source span contains "4576696c20446176652052756c7a" then "Evil Dave Rulz" is the output. + * For format specifier support, on lhe max width is used. Any @c MemSpan compatible class can be used + * as the target, including @c std::string and @c std::string_view. + * + * @code + * void f(std::string const& str) { + * w.print("{}", bwf::UnHex(str)); + * // ... + * @endcode + */ +struct UnHex { + UnHex(MemSpan const& span) : _span(span) {} + MemSpan _span; ///< Source span. +}; } // namespace bwf /** Repeatedly output a pattern. @@ -237,6 +254,8 @@ BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Errno const */ BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Date const &date); +BufferWriter &bwformat(BufferWriter &w, bwf::Spec const& spec, bwf::UnHex const& obj); + /** Output a nested formatted string. * * @tparam Args Argument pack for @a subtext. diff --git a/lib/swoc/include/swoc/bwf_std.h b/lib/swoc/include/swoc/bwf_std.h index 7003e975bea..24bd00068dd 100644 --- a/lib/swoc/include/swoc/bwf_std.h +++ b/lib/swoc/include/swoc/bwf_std.h @@ -15,6 +15,7 @@ #include "swoc/bwf_base.h" namespace swoc { inline namespace SWOC_VERSION_NS { +using namespace literals; /// Format atomics by stripping the atomic and formatting the underlying type. template @@ -48,5 +49,10 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, std::chrono::time_point T TypeFunc(); * This has no effect on @a u but fools the compiler in to thinking @a T has been used. * This avoids metaprogramming issues with unused template parameters. * - * Suppose an API has changed a function from "delain" to "Delain". To handle this the metacase support is used, but there is - * no apparent template parameter. A fake one can be used and defaulted to @c void. But that creates the unused template - * parameter warning. This is fixed by doing something like + * Suppose an API has changed a function from "cheer_for_delain" to "cheer_delain". To handle this + * the metacase support is used, but there is no apparent template parameter. A fake one can be used + * and defaulted to @c void. But that creates the unused template parameter warning. This is fixed + * by doing something to erase the template parameter @a V while forwarding parameter @a x. The result + * is a function @c f that calls the correct function automatically. Note this can't be in the body of + * the function because even for SFINAE the function body must compile and the variant with the wrong + * function will fail. + * * @code * template - * auto f(UDT x, swoc::meta::CaseTag<0>) -> decltype(delain(eraser(x))) - * { return delain(eraser(x)); } + * auto f(UDT x, swoc::meta::CaseTag<0>) -> decltype(cheer_for_delain(eraser(x))) + * { return cheer_for_delain(eraser(x)); } * * template - * auto f(UDT x, swoc::meta::CaseTag<1>) -> decltype(Delain(eraser(x))) - * { return Delain(eraser(vc)); } + * auto f(UDT x, swoc::meta::CaseTag<1>) -> decltype(cheer_delain(eraser(x))) + * { return cheer_delain(eraser(x)); } * * f(x, swoc::meta::CaseArg); // Invoke the correctly named function * @endcode diff --git a/lib/swoc/include/swoc/swoc_version.h b/lib/swoc/include/swoc/swoc_version.h index 9ebfe193c71..c7d97c71d9b 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_5_3 +#define SWOC_VERSION_NS _1_5_5 #endif namespace swoc { inline namespace SWOC_VERSION_NS { static constexpr unsigned MAJOR_VERSION = 1; static constexpr unsigned MINOR_VERSION = 5; -static constexpr unsigned POINT_VERSION = 3; +static constexpr unsigned POINT_VERSION = 5; }} // namespace swoc::SWOC_VERSION_NS diff --git a/lib/swoc/src/Errata.cc b/lib/swoc/src/Errata.cc index 80e6bea917c..9ef11fe92fc 100644 --- a/lib/swoc/src/Errata.cc +++ b/lib/swoc/src/Errata.cc @@ -142,12 +142,14 @@ bwformat(BufferWriter &bw, bwf::Spec const &spec, Errata::Severity level) { BufferWriter & bwformat(BufferWriter &bw, bwf::Spec const &, Errata const &errata) { + bwf::Format const code_fmt{"[{0:s} {0:d}] "}; + if (errata.has_severity()) { bw.print("{}{}", errata.severity(), errata.severity_glue_text()); } if (errata.code()) { - bw.print("[{0:s} {0:d}] ", errata.code()); + bw.print(code_fmt, errata.code()); } bool trailing_p = false; diff --git a/lib/swoc/src/bw_format.cc b/lib/swoc/src/bw_format.cc index ea5c2a6d47e..c586b887255 100644 --- a/lib/swoc/src/bw_format.cc +++ b/lib/swoc/src/bw_format.cc @@ -960,10 +960,10 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Pattern const &pattern) { return w; } -swoc::BufferWriter & -bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, std::error_code const &ec) { - static const auto GENERIC_CATEGORY = &std::generic_category(); - static const auto SYSTEM_CATEGORY = &std::system_category(); +BufferWriter & +bwformat(BufferWriter &w, bwf::Spec const &spec, std::error_code const &ec) { + static const auto G_CAT = &std::generic_category(); + static const auto S_CAT = &std::system_category(); // This provides convenient safe access to the errno short name array. static const swoc::bwf::Format number_fmt{"[{}]"_sv}; // numeric value format. @@ -971,19 +971,30 @@ bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, std::error_code con // if numeric type, print just the numeric part. bwformat(w, spec, ec.value()); } else { - if ((&ec.category() == GENERIC_CATEGORY || &ec.category() == SYSTEM_CATEGORY) && swoc::ERRNO_RANGE.contains(ec.value())) { + if ((&ec.category() == G_CAT || &ec.category() == S_CAT) && swoc::ERRNO_RANGE.contains(ec.value())) { bwformat(w, spec, swoc::ERRNO_SHORT_NAME[ec.value()]); } else { w.write(ec.message()); } if (spec._type != 's' && spec._type != 'S') { - w.write(' '); - w.print(number_fmt, ec.value()); + bwformat(w, spec, ec.value()); + w.write(' ').write('[').format(spec, ec.value()).write(']'); } } return w; } +BufferWriter& +bwformat(BufferWriter &w, bwf::Spec const& spec, bwf::UnHex const& obj) { + auto span { obj._span }; + size_t limit = spec._max; + while (span.size() >= 2 && limit--) { + auto b = svto_radix<16>(span.clip_prefix(2).rebind()); + w.write(b); + } + return w; +} + }} // namespace swoc::SWOC_VERSION_NS namespace std {