This is an automated email from the ASF dual-hosted git repository.

bneradt pushed a commit to branch charset
in repository https://gitbox.apache.org/repos/asf/trafficserver-libswoc.git

commit 3632bbcbcfd146fc6480a7226872e8e5b00a49f5
Author: Alan M. Carroll <[email protected]>
AuthorDate: Tue Nov 21 16:37:06 2023 -0600

    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 @@ public:
   /// 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 @@ protected:
     bool _glue_final_p                      = true; ///< Add glue after the 
last annotation?
 
     std::optional<Severity> _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 @@ public:
   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 @@ public:
    */
   self_type &ltrim(char c);
 
+  /** Remove bytes from the start of the view that are in @a delimiters.
+   *
+   * @return @a this
+   */
+  self_type &ltrim(CharSet const &delimiters);
+
   /** Remove bytes from the start of the view that are in @a delimiters.
    *
    * @return @a this
@@ -350,6 +368,12 @@ public:
    */
   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 @@ public:
    */
   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<uint8_t>(*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<uint8_t>(*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<uint8_t>(*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<uint8_t>(*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 <typename F>
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<swoc::TextView, 5> 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<ECode> 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]");
+}

Reply via email to