From 3632bbcbcfd146fc6480a7226872e8e5b00a49f5 Mon Sep 17 00:00:00 2001 From: "Alan M. Carroll" Date: Tue, 21 Nov 2023 16:37:06 -0600 Subject: [PATCH 1/3] Errata: Enable auto generated annotations. --- code/include/swoc/Errata.h | 87 ++++++++++++++++++++++++++++++++---- code/include/swoc/TextView.h | 86 ++++++++++++++++++++++++++--------- code/src/bw_format.cc | 4 +- unit_tests/test_Errata.cc | 46 +++++++++++++++++++ 4 files changed, 190 insertions(+), 33 deletions(-) diff --git a/code/include/swoc/Errata.h b/code/include/swoc/Errata.h index 59ec0d4..8d3c129 100644 --- a/code/include/swoc/Errata.h +++ b/code/include/swoc/Errata.h @@ -47,6 +47,7 @@ #include "swoc/MemSpan.h" #include "swoc/MemArena.h" #include "swoc/bwf_base.h" +#include "swoc/bwf_std.h" #include "swoc/IntrusiveDList.h" namespace swoc { inline namespace SWOC_VERSION_NS { @@ -85,6 +86,10 @@ class Errata { /// This defaults to zero and no filtering is done unless it is overwritten. static Severity FILTER_SEVERITY; + static inline TextView AUTOTEXT_SEVERITY = "{}"; ///< Format for auto generated annotation with severity. + static inline TextView AUTOTEXT_CODE = "{}"; ///< Format for auto generated annotation with error code. + static inline TextView AUTOTEXT_SEVERITY_CODE = "{}: {}"; ///< Format for auto generate annotation with error code and severity. + /// Mapping of severity to string. /// Values larger than the span size will be rendered as numbers. /// Defaults to an empty span, meaning all severities will be printed as integers. @@ -196,28 +201,77 @@ class Errata { bool _glue_final_p = true; ///< Add glue after the last annotation? std::optional _severity; ///< Severity. - code_type _code{Errata::DEFAULT_CODE}; ///< Message code / ID + code_type _code{DEFAULT_CODE}; ///< Message code / ID Container _notes; ///< The message stack. swoc::MemArena _arena; ///< Annotation text storage. }; public: + /// Used to indicate automatically generated annotation text. + static constexpr struct AutoText {} AUTO {}; + /// Default constructor - empty errata, very fast. Errata() = default; - Errata(self_type const &that) = delete; ///< No constant copy construction. + Errata(self_type const &that) = delete; ///< No copy construction. Errata(self_type &&that) noexcept; ///< Move constructor. - self_type &operator=(self_type const &that) = delete; // no copy assignemnt. + self_type &operator=(self_type const &that) = delete; // no copy assignment. self_type &operator=(self_type &&that); ///< Move assignment. ~Errata(); ///< Destructor. + /** Construct with an error code. + * + * @param ec Error code + * + * No annotation is created. + */ + explicit Errata(code_type const& ec); + + /** Construct with an error code and generated annotation. + * + * @param ec Error code + * + * An annotation is created using the format @c AUTOTEXT_CODE with @a ec as the argument. + * @see AUTOTEXT_CODE + */ + explicit Errata(code_type const& ec, AutoText); + /** Construct with a severity. * * @param severity Severity. * - * No annotations are created. + * No annotation is created. */ explicit Errata(Severity severity); + /** Construct with a severity. + * + * @param severity Severity. + * + * An annotation is created using the format @c AUTO_TEXT_SEVERITY with @a severity as the argument. + * @see AUTOTEXT_SEVERITY + */ + explicit Errata(Severity severity, AutoText); + + /** Construct with error code and severity. + * + * @param ec Error code. + * @param severity Severity. + * + * No annotation is created. + */ + Errata(code_type const &ec, Severity severity); + + /** Construct with a severity and error code. + * + * @param severity Severity. + * @param ec Error code. + * @param auto_text If present, generate an annotation. + * + * The annotation uses the format @c AUTOTEXT_SEVERITY_CODE with arguments @a severity , @a ec + * @see AUTOTEXT_SEVERITY_CODE + */ + explicit Errata(code_type const& ec, Severity severity, AutoText auto_text); + /** Constructor. * * @param code Error code. @@ -613,9 +667,6 @@ class Errata { std::ostream &write(std::ostream &out) const; protected: - /// Construct with code and severity, but no annotations. - Errata(code_type const &code, Severity severity); - /// Implementation instance. /// @internal Because this is used with a self-containing @c MemArena standard smart pointers do not /// work correctly. Instead the @c clear method must be used to release the memory. @@ -979,14 +1030,32 @@ inline Errata::Errata(self_type &&that) noexcept { std::swap(_data, that._data); } +inline Errata::Errata(code_type const& ec) { + this->data()->_code = ec; +} + inline Errata::Errata(Severity severity) { this->data()->_severity = severity; } -inline Errata::Errata(const code_type &code, Severity severity) { +inline Errata::Errata(const code_type &ec, Severity severity) { auto d = this->data(); d->_severity = severity; - d->_code = code; + d->_code = ec; +} + +inline Errata::Errata(code_type const& ec, AutoText) { + this->data()->_code = ec; + this->note(AUTOTEXT_CODE, ec); +} + +inline Errata::Errata(Severity severity, AutoText) { + this->data()->_severity = severity; + this->note(AUTOTEXT_SEVERITY, severity); +} + +inline Errata::Errata(const code_type &ec, Severity severity, AutoText) : Errata(ec, severity) { + this->note(AUTOTEXT_SEVERITY_CODE, severity, ec); } inline Errata::Errata(const code_type &code, Severity severity, const std::string_view &text) : Errata(code, severity) { diff --git a/code/include/swoc/TextView.h b/code/include/swoc/TextView.h index b665f54..ed342ee 100644 --- a/code/include/swoc/TextView.h +++ b/code/include/swoc/TextView.h @@ -36,6 +36,18 @@ namespace swoc { inline namespace SWOC_VERSION_NS { class TextView; +/** A set of characters. + * + */ +class CharSet { + using self_type = CharSet; +public: + constexpr CharSet(TextView const& chars); + bool operator () (u_char idx) const { return _chars[idx]; } +protected: + std::bitset<256> _chars; +}; + /** A read only view of a contiguous piece of memory. A @c TextView does not own the memory to which it refers, it is simply a view of part of some @@ -324,6 +336,12 @@ class TextView : public std::string_view { */ self_type <rim(char c); + /** Remove bytes from the start of the view that are in @a delimiters. + * + * @return @a this + */ + self_type <rim(CharSet const &delimiters); + /** Remove bytes from the start of the view that are in @a delimiters. * * @return @a this @@ -350,6 +368,12 @@ class TextView : public std::string_view { */ self_type &rtrim(char c); + /** Remove bytes from the end of the view that are in @a delimiters. + * + * @return @a this + */ + self_type &rtrim(CharSet const &delimiters); + /** Remove bytes from the end of the view that are in @a delimiters. * @return @a this */ @@ -369,6 +393,11 @@ class TextView : public std::string_view { */ self_type &trim(char c); + /** Remove bytes from the start and end of the view that are in @a delimiters. + * @return @a this + */ + self_type &trim(CharSet const &delimiters); + /** Remove bytes from the start and end of the view that are in @a delimiters. * @return @a this */ @@ -1052,6 +1081,12 @@ double svtod(TextView text, TextView *parsed = nullptr); // simpler plain @c TextView ? Because otherwise Doxygen can't match up the declaration and // definition and the reference documentation is messed up. Sigh. +inline constexpr CharSet::CharSet(TextView const & chars) { + for ( auto c : chars) { + _chars[u_char(c)] = true; + } +} + // === TextView Implementation === /// @cond TextView_INTERNAL // Doxygen doesn't match these up well due to various type and template issues. @@ -1474,62 +1509,71 @@ TextView::trim(char c) { } inline TextView & -TextView::ltrim(std::string_view const &delimiters) { - std::bitset<256> valid; - this->init_delimiter_set(delimiters, valid); - const char *spot; - const char *limit; +TextView::ltrim(CharSet const &delimiters) { + const char *spot = this->data(); + const char *limit = this->data_end(); - for (spot = this->data(), limit = this->data_end(); spot < limit && valid[static_cast(*spot)]; ++spot) - ; + while (spot < limit && delimiters(*spot)) { + ++spot; + } this->remove_prefix(spot - this->data()); return *this; } +inline TextView & +TextView::ltrim(std::string_view const &delimiters) { + return this->ltrim(CharSet(delimiters)); +} + inline TextView & TextView::ltrim(const char *delimiters) { - return this->ltrim(std::string_view(delimiters)); + return this->ltrim(CharSet(delimiters)); } inline TextView & -TextView::rtrim(std::string_view const &delimiters) { - std::bitset<256> valid; - this->init_delimiter_set(delimiters, valid); +TextView::rtrim(CharSet const &delimiters) { const char *spot = this->data_end(); const char *limit = this->data(); - - while (limit < spot-- && valid[static_cast(*spot)]) - ; + while (limit < spot-- && delimiters(*spot)) { + } this->remove_suffix(this->data_end() - (spot + 1)); return *this; } inline TextView & -TextView::trim(std::string_view const &delimiters) { - std::bitset<256> valid; - this->init_delimiter_set(delimiters, valid); +TextView::rtrim(std::string_view const &delimiters) { + return this->rtrim(CharSet(delimiters)); +} + +inline TextView & +TextView::trim(CharSet const &delimiters) { const char *spot; const char *limit; // Do this explicitly, so we don't have to initialize the character set twice. - for (spot = this->data(), limit = this->data_end(); spot < limit && valid[static_cast(*spot)]; ++spot) + for (spot = this->data(), limit = this->data_end(); spot < limit && delimiters(*spot); ++spot) ; this->remove_prefix(spot - this->data()); spot = this->data_end(); limit = this->data(); - while (limit < spot-- && valid[static_cast(*spot)]) - ; + while (limit < spot-- && delimiters(*spot)) { + } this->remove_suffix(this->data_end() - (spot + 1)); return *this; } +inline TextView & +TextView::trim(std::string_view const &delimiters) { + return this->trim(CharSet(delimiters)); +} + inline TextView & TextView::trim(const char *delimiters) { - return this->trim(std::string_view(delimiters)); + return this->trim(CharSet(delimiters)); } template diff --git a/code/src/bw_format.cc b/code/src/bw_format.cc index de62200..83f1689 100644 --- a/code/src/bw_format.cc +++ b/code/src/bw_format.cc @@ -905,8 +905,7 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, std::error_code const &ec) { // This provides convenient safe access to the errno short name array. static const swoc::bwf::Format number_fmt{"[{}]"_sv}; // numeric value format. - if (spec.has_numeric_type()) { - // if numeric type, print just the numeric part. + if (spec.has_numeric_type()) { // if numeric type, print just the numeric part. bwformat(w, spec, ec.value()); } else { if ((&ec.category() == G_CAT || &ec.category() == S_CAT) && swoc::ERRNO_RANGE.contains(ec.value())) { @@ -915,7 +914,6 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, std::error_code const &ec) { w.write(ec.message()); } if (spec._type != 's' && spec._type != 'S') { - bwformat(w, spec, ec.value()); w.write(' ').write('[').format(spec, ec.value()).write(']'); } } diff --git a/unit_tests/test_Errata.cc b/unit_tests/test_Errata.cc index acb41a0..da766ca 100644 --- a/unit_tests/test_Errata.cc +++ b/unit_tests/test_Errata.cc @@ -10,6 +10,7 @@ #include "swoc/bwf_std.h" #include "swoc/bwf_ex.h" #include "swoc/swoc_file.h" +#include "swoc/Lexicon.h" #include "catch.hpp" using swoc::Errata; @@ -29,6 +30,42 @@ std::array Severity_Names{ {"Debug", "Diag", "Info", "Warn", "Error"} }; +enum class ECode { + ALPHA = 1, + BRAVO, + CHARLIE +}; + +struct e_category : std::error_category { + const char *name() const noexcept override; + std::string message(int ev) const override; +}; + +e_category e_cat; + +const char * +e_category::name() const noexcept +{ + return "libswoc"; +} + +std::string +e_category::message(int ev) const +{ + static swoc::Lexicon lexicon { + { + { ECode::ALPHA , "Alpha" }, + { ECode::BRAVO, "Bravo"}, + { ECode::CHARLIE, "Charlie"} + } + , "Code out of range" + }; + + return std::string(lexicon[ECode(ev)]); +} + +inline std::error_code ecode(ECode c) { return { int(c) , e_cat }; } + std::string ErrataSinkText; // Call from unit test main before starting tests. @@ -376,3 +413,12 @@ TEST_CASE("Errata Wrapper", "[libswoc][errata]") { REQUIRE(errata.front().text().starts_with("ni itchi - EINVAL")); } } + +TEST_CASE("Errata Autotext", "[libswoc][errata]") { + Errata a{ERRATA_WARN, Errata::AUTO}; + REQUIRE(a.front().text() == "Warn"); + Errata b{ecode(ECode::BRAVO), Errata::AUTO}; + REQUIRE(b.front().text() == "Bravo [2]"); + Errata c{ecode(ECode::ALPHA), ERRATA_ERROR, Errata::AUTO}; + REQUIRE(c.front().text() == "Error: Alpha [1]"); +} From 6ab1f574d2259c833f61c2514d3ce852300867af Mon Sep 17 00:00:00 2001 From: "Alan M. Carroll" Date: Tue, 21 Nov 2023 16:38:30 -0600 Subject: [PATCH 2/3] Clang format. --- code/include/swoc/Errata.h | 25 +++++++++++++------------ code/include/swoc/TextView.h | 15 ++++++++++----- code/src/bw_format.cc | 2 +- unit_tests/test_Errata.cc | 27 ++++++++++----------------- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/code/include/swoc/Errata.h b/code/include/swoc/Errata.h index 8d3c129..944129d 100644 --- a/code/include/swoc/Errata.h +++ b/code/include/swoc/Errata.h @@ -86,8 +86,8 @@ class Errata { /// This defaults to zero and no filtering is done unless it is overwritten. static Severity FILTER_SEVERITY; - static inline TextView AUTOTEXT_SEVERITY = "{}"; ///< Format for auto generated annotation with severity. - static inline TextView AUTOTEXT_CODE = "{}"; ///< Format for auto generated annotation with error code. + static inline TextView AUTOTEXT_SEVERITY = "{}"; ///< Format for auto generated annotation with severity. + static inline TextView AUTOTEXT_CODE = "{}"; ///< Format for auto generated annotation with error code. static inline TextView AUTOTEXT_SEVERITY_CODE = "{}: {}"; ///< Format for auto generate annotation with error code and severity. /// Mapping of severity to string. @@ -200,15 +200,16 @@ class Errata { TextView _indent_text = DEFAULT_INDENT_TEXT; bool _glue_final_p = true; ///< Add glue after the last annotation? - std::optional _severity; ///< Severity. - code_type _code{DEFAULT_CODE}; ///< Message code / ID - Container _notes; ///< The message stack. - swoc::MemArena _arena; ///< Annotation text storage. + std::optional _severity; ///< Severity. + code_type _code{DEFAULT_CODE}; ///< Message code / ID + Container _notes; ///< The message stack. + swoc::MemArena _arena; ///< Annotation text storage. }; public: /// Used to indicate automatically generated annotation text. - static constexpr struct AutoText {} AUTO {}; + static constexpr struct AutoText { + } AUTO{}; /// Default constructor - empty errata, very fast. Errata() = default; @@ -224,7 +225,7 @@ class Errata { * * No annotation is created. */ - explicit Errata(code_type const& ec); + explicit Errata(code_type const &ec); /** Construct with an error code and generated annotation. * @@ -233,7 +234,7 @@ class Errata { * An annotation is created using the format @c AUTOTEXT_CODE with @a ec as the argument. * @see AUTOTEXT_CODE */ - explicit Errata(code_type const& ec, AutoText); + explicit Errata(code_type const &ec, AutoText); /** Construct with a severity. * @@ -270,7 +271,7 @@ class Errata { * The annotation uses the format @c AUTOTEXT_SEVERITY_CODE with arguments @a severity , @a ec * @see AUTOTEXT_SEVERITY_CODE */ - explicit Errata(code_type const& ec, Severity severity, AutoText auto_text); + explicit Errata(code_type const &ec, Severity severity, AutoText auto_text); /** Constructor. * @@ -1030,7 +1031,7 @@ inline Errata::Errata(self_type &&that) noexcept { std::swap(_data, that._data); } -inline Errata::Errata(code_type const& ec) { +inline Errata::Errata(code_type const &ec) { this->data()->_code = ec; } @@ -1044,7 +1045,7 @@ inline Errata::Errata(const code_type &ec, Severity severity) { d->_code = ec; } -inline Errata::Errata(code_type const& ec, AutoText) { +inline Errata::Errata(code_type const &ec, AutoText) { this->data()->_code = ec; this->note(AUTOTEXT_CODE, ec); } diff --git a/code/include/swoc/TextView.h b/code/include/swoc/TextView.h index ed342ee..41ed9ba 100644 --- a/code/include/swoc/TextView.h +++ b/code/include/swoc/TextView.h @@ -41,9 +41,14 @@ class TextView; */ class CharSet { using self_type = CharSet; + public: - constexpr CharSet(TextView const& chars); - bool operator () (u_char idx) const { return _chars[idx]; } + constexpr CharSet(TextView const &chars); + bool + operator()(u_char idx) const { + return _chars[idx]; + } + protected: std::bitset<256> _chars; }; @@ -1081,8 +1086,8 @@ double svtod(TextView text, TextView *parsed = nullptr); // simpler plain @c TextView ? Because otherwise Doxygen can't match up the declaration and // definition and the reference documentation is messed up. Sigh. -inline constexpr CharSet::CharSet(TextView const & chars) { - for ( auto c : chars) { +inline constexpr CharSet::CharSet(TextView const &chars) { + for (auto c : chars) { _chars[u_char(c)] = true; } } @@ -1510,7 +1515,7 @@ TextView::trim(char c) { inline TextView & TextView::ltrim(CharSet const &delimiters) { - const char *spot = this->data(); + const char *spot = this->data(); const char *limit = this->data_end(); while (spot < limit && delimiters(*spot)) { diff --git a/code/src/bw_format.cc b/code/src/bw_format.cc index 83f1689..60ceacc 100644 --- a/code/src/bw_format.cc +++ b/code/src/bw_format.cc @@ -905,7 +905,7 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, std::error_code const &ec) { // This provides convenient safe access to the errno short name array. static const swoc::bwf::Format number_fmt{"[{}]"_sv}; // numeric value format. - if (spec.has_numeric_type()) { // if numeric type, print just the numeric part. + if (spec.has_numeric_type()) { // if numeric type, print just the numeric part. bwformat(w, spec, ec.value()); } else { if ((&ec.category() == G_CAT || &ec.category() == S_CAT) && swoc::ERRNO_RANGE.contains(ec.value())) { diff --git a/unit_tests/test_Errata.cc b/unit_tests/test_Errata.cc index da766ca..8ce82a5 100644 --- a/unit_tests/test_Errata.cc +++ b/unit_tests/test_Errata.cc @@ -30,11 +30,7 @@ std::array Severity_Names{ {"Debug", "Diag", "Info", "Warn", "Error"} }; -enum class ECode { - ALPHA = 1, - BRAVO, - CHARLIE -}; +enum class ECode { ALPHA = 1, BRAVO, CHARLIE }; struct e_category : std::error_category { const char *name() const noexcept override; @@ -44,27 +40,24 @@ struct e_category : std::error_category { e_category e_cat; const char * -e_category::name() const noexcept -{ +e_category::name() const noexcept { return "libswoc"; } std::string -e_category::message(int ev) const -{ - static swoc::Lexicon lexicon { - { - { ECode::ALPHA , "Alpha" }, - { ECode::BRAVO, "Bravo"}, - { ECode::CHARLIE, "Charlie"} - } - , "Code out of range" +e_category::message(int ev) const { + static swoc::Lexicon lexicon{ + {{ECode::ALPHA, "Alpha"}, {ECode::BRAVO, "Bravo"}, {ECode::CHARLIE, "Charlie"}}, + "Code out of range" }; return std::string(lexicon[ECode(ev)]); } -inline std::error_code ecode(ECode c) { return { int(c) , e_cat }; } +inline std::error_code +ecode(ECode c) { + return {int(c), e_cat}; +} std::string ErrataSinkText; From 032c6a12a84e161c20a69f16a432c08a483e0d8c Mon Sep 17 00:00:00 2001 From: "Alan M. Carroll" Date: Tue, 21 Nov 2023 16:44:21 -0600 Subject: [PATCH 3/3] IPAddr: make copy_to const --- code/include/swoc/IPAddr.h | 2 +- code/src/swoc_ip.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/include/swoc/IPAddr.h b/code/include/swoc/IPAddr.h index 690ee14..50d14af 100644 --- a/code/include/swoc/IPAddr.h +++ b/code/include/swoc/IPAddr.h @@ -579,7 +579,7 @@ class IPAddr { * @param sa Destination. * @return @a sa */ - sockaddr *copy_to(sockaddr *sa); + sockaddr *copy_to(sockaddr *sa) const; /** Parse a string and load the result in @a this. * diff --git a/code/src/swoc_ip.cc b/code/src/swoc_ip.cc index 67fc9fa..0ddc9bb 100644 --- a/code/src/swoc_ip.cc +++ b/code/src/swoc_ip.cc @@ -515,7 +515,7 @@ IPAddr::operator=(IPEndpoint const &addr) { } sockaddr * -IPAddr::copy_to(sockaddr *sa) { +IPAddr::copy_to(sockaddr *sa) const { if (this->is_ip4()) { _addr._ip4.copy_to(sa); } else if (this->is_ip6()) {