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

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

commit a95c8ec34e14d5bbf0bc214ed9c119603212a6a2
Author: Alan M. Carroll <a...@apache.org>
AuthorDate: Fri Sep 17 12:05:25 2021 -0500

    Errata refactor - Unit tests working.
---
 code/include/swoc/DiscreteRange.h |   2 +-
 code/include/swoc/Errata.h        | 358 +++++++++++++-------------------------
 code/src/Errata.cc                | 103 ++++-------
 code/src/bw_format.cc             | 174 ++++++++++++++++--
 doc/code/Errata.en.rst            | 129 ++++++++++----
 doc/index.rst                     |   1 +
 unit_tests/ex_Errata_Severity.h   |  20 ---
 unit_tests/ex_UnitParser.cc       |  15 +-
 unit_tests/test_Errata.cc         | 138 ++++++++-------
 unit_tests/unit_test_main.cc      |   7 +
 10 files changed, 504 insertions(+), 443 deletions(-)

diff --git a/code/include/swoc/DiscreteRange.h 
b/code/include/swoc/DiscreteRange.h
index 4a93ffd..89ffecf 100644
--- a/code/include/swoc/DiscreteRange.h
+++ b/code/include/swoc/DiscreteRange.h
@@ -178,7 +178,7 @@ public:
    * @param m Metric value to check.
    * @return @c true if @a m is in the range, @c false if not.
    */
-  bool contains(metric_type const& m) {
+  bool contains(metric_type const& m) const {
     return _min <= m && m <= _max;
   }
 
diff --git a/code/include/swoc/Errata.h b/code/include/swoc/Errata.h
index 4634e6b..c7f7fa2 100644
--- a/code/include/swoc/Errata.h
+++ b/code/include/swoc/Errata.h
@@ -74,6 +74,10 @@ public:
   static Severity DEFAULT_SEVERITY;
   /// Severity level at which the instance is a failure of some sort.
   static Severity FAILURE_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.
+  static MemSpan<TextView> SEVERITY_NAME;
 
   /** An annotation to the Errata consisting of a severity and informative 
text.
    *
@@ -85,24 +89,18 @@ public:
     /// The message has default severity and empty text.
     Annotation();
 
-    /** Construct with severity @a level and @a text.
+    /** Construct with @a text.
      *
-     * @param severity Severity level.
      * @param text Annotation content (literal).
      *
      * @a text is presumed to be stable for the @c Annotation lifetime, it is 
not maintained
      * locally.
      */
-    Annotation(code_type const& code, Severity severity, std::string_view 
text);
+    explicit Annotation(std::string_view text);
 
     /// Reset to the message to default state.
     self_type &clear();
 
-    code_type code() const;
-
-    /// Get the severity.
-    Severity severity() const;
-
     /// Get the text of the message.
     std::string_view text() const;
 
@@ -112,14 +110,9 @@ public:
     /// Set the text of the message.
     self_type &assign(std::string_view text);
 
-    /// Set the severity @a level
-    self_type &assign(Severity level);
-
   protected:
     std::string_view _text;                       ///< Annotation text.
-    code_type _code;                              ///< Message code / ID
     unsigned short _level{0};                     ///< Nesting level.
-    Severity _severity{Errata::DEFAULT_SEVERITY}; ///< Severity.
 
     /// @{{
     /// Policy and links for intrusive list.
@@ -145,7 +138,9 @@ protected:
   struct Data {
     using self_type = Data; ///< Self reference type.
 
-    /// Construct into @c MemArena.
+    /// Construct and take ownership of @a arena.
+    /// @internal This assumes the instance is being constructed in @a arena 
and therefore transfers the
+    /// @a arena into internal storage so that everything is in the @a arena.
     Data(swoc::MemArena &&arena);
 
     /// Check if there are any notes.
@@ -158,34 +153,39 @@ protected:
      */
     std::string_view localize(std::string_view src);
 
-    /// Get the remnant of the curret block in the arena.
+    /// Get the remnant of the current block in the arena.
     swoc::MemSpan<char> remnant();
 
     /// Allocate from the arena.
     swoc::MemSpan<char> alloc(size_t n);
 
-    /// Reference count.
-    std::atomic<int> _ref_count{0};
-
-    /// The message stack.
-    Container _notes;
-    /// Annotation text storage.
-    swoc::MemArena _arena;
-    /// Nesting level.
-    unsigned _level{0};
-    /// The effective severity of the message stack.
-    Severity _severity{0};
+    Severity _severity{Errata::DEFAULT_SEVERITY}; ///< Severity.
+    code_type _code{Errata::DEFAULT_CODE};        ///< Message code / ID
+    unsigned _level{0};                           ///< Nesting level.
+    std::atomic<int> _ref_count{0};               ///< Reference count.
+    Container _notes;                             ///< The message stack.
+    swoc::MemArena _arena;                        ///< Annotation text storage.
   };
 
 public:
   /// Default constructor - empty errata, very fast.
   Errata() = default;
-  Errata(self_type const &that);                                   ///< 
Reference counting copy constructor.
+  Errata(self_type const& that) = delete; ///< No constant 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 &&that); ///< Move 
assignment.
   ~Errata();                                                       ///< 
Destructor.
 
+  // Note based constructors.
+  Errata(code_type const& type, Severity severity, std::string_view const& 
text);
+  Errata(Severity severity, std::string_view const& text);
+  Errata(code_type const& type, std::string_view const& text);
+  explicit Errata(std::string_view const& text);
+  template <typename... Args> Errata(code_type const& type, Severity severity, 
std::string_view fmt, Args &&... args);
+  template <typename... Args> Errata(code_type const& type, std::string_view 
fmt, Args &&... args);
+  template <typename... Args> Errata(Severity severity, std::string_view fmt, 
Args &&... args);
+  template <typename... Args> explicit Errata(std::string_view fmt, Args &&... 
args);
+
   /** Add a new message to the top of stack with severity @a level and @a text.
    * @param text Text of the message.
    * @return *this
@@ -194,46 +194,14 @@ public:
    */
   self_type &note(std::string_view text);
 
-  /** Add a new message to the top of stack with severity @a level and @a text.
-   * @param text Text of the message.
-   * @param severity Severity of the message.
-   * @return *this
-   */
-  self_type &note(Severity severity, std::string_view text);
-
   /** Add a new message to the top of stack with severity @a level and @a text.
    * @param code Error code.
    * @return *this
    *
-   * The text message is constructed as the short, long, and numeric value of 
@a code.
+   * The annotation text is constructed as the short, long, and numeric value 
of @a code, which is then discarded.
    */
   self_type &note(code_type const& code);
 
-  /** Add a new message to the top of stack with severity @a level and @a text.
-   * @param code Error code.
-   * @param severity Severity of the message.
-   * @param text Text of the message.
-   * @return *this
-   *
-   * The text message is constructed as the short, long, and numeric value of 
@a code.
-   */
-  self_type &note(code_type const& code, Severity severity);
-
-  /** Add a new message to the top of stack with severity @a level and @a text.
-   * @param code Error code.
-   * @param text Text of the message.
-   * @return *this
-   */
-  self_type &note(code_type const& code, std::string_view text);
-
-  /** Add a new message to the top of stack with severity @a level and @a text.
-   * @param code Error code.
-   * @param severity Severity of the message.
-   * @param text Text of the message.
-   * @return *this
-   */
-  self_type &note(code_type const& code, Severity severity, std::string_view 
text);
-
   /** Push a constructed @c Annotation.
       The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
       to strings and concatenated to form the messsage text.
@@ -241,27 +209,6 @@ public:
   */
   template <typename... Args> self_type &note(std::string_view fmt, Args &&... 
args);
 
-  /** Push a constructed @c Annotation.
-      The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
-      to strings and concatenated to form the messsage text.
-      @return A reference to this object.
-  */
-  template <typename... Args> self_type &note(code_type const& code, 
std::string_view fmt, Args &&... args);
-
-  /** Push a constructed @c Annotation.
-      The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
-      to strings and concatenated to form the messsage text.
-      @return A reference to this object.
-  */
-  template <typename... Args> self_type &note(Severity severity, 
std::string_view fmt, Args &&... args);
-
-  /** Push a constructed @c Annotation.
-      The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
-      to strings and concatenated to form the messsage text.
-      @return A reference to this object.
-  */
-  template <typename... Args> self_type &note(code_type const& code, Severity 
severity, std::string_view fmt, Args &&... args);
-
   /** Push a constructed @c Annotation.
       The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
       to strings and concatenated to form the messsage text.
@@ -269,38 +216,21 @@ public:
   */
   template <typename... Args> self_type &note_v(std::string_view fmt, 
std::tuple<Args...> const &args);
 
-  /** Push a constructed @c Annotation.
-      The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
-      to strings and concatenated to form the messsage text.
-      @return A reference to this object.
-  */
-  template <typename... Args> self_type &note_v(Severity severity, 
std::string_view fmt, std::tuple<Args...> const &args);
-
-  /** Push a constructed @c Annotation.
-      The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
-      to strings and concatenated to form the messsage text.
-      @return A reference to this object.
-  */
-  template <typename... Args> self_type &note_v(code_type const& code, 
std::string_view fmt, std::tuple<Args...> const &args);
-
-  /** Push a constructed @c Annotation.
-      The @c Annotation is set to have the @a id and @a code. The other 
arguments are converted
-      to strings and concatenated to form the messsage text.
-      @return A reference to this object.
-  */
-  template <typename... Args> self_type &note_v(code_type const& code, 
Severity severity, std::string_view fmt, std::tuple<Args...> const &args);
-
   /** Copy messages from @a that to @a this.
    *
    * @param that Source object from which to copy.
    * @return @a *this
+   *
+   * The code and severity of @a that are discarded.
    */
   self_type &note(self_type const &that);
 
-  /** Copye messages from @a that to @a this, then clear @a that.
+  /** Copy messages from @a that to @a this, then clear @a that.
    *
    * @param that Source object from which to copy.
    * @return @a *this
+   *
+   * The code and severity of @a that are discarded.
    */
   self_type &note(self_type &&that);
 
@@ -421,23 +351,21 @@ public:
   std::ostream &write(std::ostream &out) const;
 
 protected:
-  /// Release internal memory.
-  void release();
+  /// Construct with code and severity, but no annotations.
+  Errata(code_type const& code, Severity severity);
 
   /// Implementation instance.
-  // Although it may seem like move semantics make reference counting 
unnecessary, that's not the
-  // case. The problem is code that wants to work with an instance, which is 
common. In such cases
-  // the instance is constructed just as it is returned (e.g. std::string). 
Code would therefore
-  // have to call std::move for every return, which is not going to be done 
reliably.
-  Data *_data{nullptr};
+  /// @internal Because this is used with a self-containing @c MemArena 
standard smart pointers do not
+  /// work correctly. Instead the @c reset method must be used to release the 
memory.
+  /// @see reset
+  Data * _data = nullptr;
 
   /// Force data existence.
   /// @return A pointer to the data.
-  const Data *data();
+  Data *data();
 
-  /// Get a writeable data pointer.
-  /// @internal It is a fatal error to ask for writeable data if there are 
shared references.
-  Data *writeable_data();
+  /// Destroy the data.
+  void reset();
 
   /** Allocate a span of memory.
    *
@@ -446,8 +374,8 @@ protected:
    */
   MemSpan<char> alloc(size_t n);
 
-  /// Add a note which is already localized.
-  self_type &note_localized(code_type const& code, Severity, std::string_view 
const &text);
+  /// Add a note, localizing the @a text.
+  self_type &note_localized(std::string_view const &text);
 
   /// Used for returns when no data is present.
   static Annotation const NIL_NOTE;
@@ -538,50 +466,28 @@ public:
 
   /** Push a message in to the result.
    *
-   * @param level Severity of the message.
-   * @param text Text of the message.
+   * @param Code the error code.
    * @return @a *this
-   */
-  self_type &note(code_type const& code);
-
-  /** Push a message in to the result.
    *
-   * @param level Severity of the message.
-   * @param text Text of the message.
-   * @return @a *this
-   */
-  self_type &note(Severity level, std::string_view text);
-
-  /** Push a message in to the result.
-   *
-   * @param level Severity of the message.
-   * @param text Text of the message.
-   * @return @a *this
+   * The annotation text is constructed as the short, long, and numeric value 
of @a code, which is then discarded.
    */
-  self_type &note(code_type const& code, std::string_view text);
-
-  /** Push a message in to the result.
-   *
-   * @param level Severity of the message.
-   * @param text Text of the message.
-   * @return @a *this
-   */
-  self_type &note(code_type const& code, Severity level, std::string_view 
text);
+  self_type &note(code_type const& code);
 
   /** Push a message in to the result.
    *
    * @tparam Args Format string argument types.
-   * @param level Severity of the message.
    * @param fmt Format string.
    * @param args Arguments for @a fmt.
    * @return @a *this
    */
-  template <typename... Args> self_type &note(Severity level, std::string_view 
fmt, Args &&... args);
+  template <typename... Args> self_type &note(std::string_view fmt, Args &&... 
args);
 
   /** Copy messages from @a that to @a this.
    *
    * @param that Source object from which to copy.
    * @return @a *this
+   *
+   * The code and severity of @a that are discarded.
    */
   self_type &note(Errata const &that);
 
@@ -589,6 +495,8 @@ public:
    *
    * @param that Source object from which to copy.
    * @return @a *this
+   *
+   * The code and severity of @a that are discarded.
    */
   self_type &note(Errata &&that);
 
@@ -686,6 +594,8 @@ public:
    *
    * @param status Errata to move in to this instance.
    * @return *this
+   *
+   * The current @c Errata for @a this is discarded and replaced with @a 
status.
    */
   self_type &operator=(Errata &&status);
 
@@ -713,13 +623,12 @@ MakeRv(R &&r,           ///< The function result
 /* ----------------------------------------------------------------------- */
 // Inline methods for Annotation
 
-inline Errata::Annotation::Annotation() {}
+inline Errata::Annotation::Annotation() = default;
 
-inline Errata::Annotation::Annotation(code_type const& code, Severity 
severity, std::string_view text) : _text(text), _code(code), 
_severity(severity) {}
+inline Errata::Annotation::Annotation(std::string_view text) : _text(text) {}
 
 inline Errata::Annotation &
 Errata::Annotation::clear() {
-  _severity = Errata::DEFAULT_SEVERITY;
   _text     = std::string_view{};
   return *this;
 }
@@ -734,22 +643,12 @@ Errata::Annotation::level() const {
   return _level;
 }
 
-inline Errata::Severity
-Errata::Annotation::severity() const {
-  return _severity;
-}
-
 inline Errata::Annotation &
 Errata::Annotation::assign(std::string_view text) {
   _text = text;
   return *this;
 }
 
-inline Errata::Annotation &
-Errata::Annotation::assign(Severity level) {
-  _severity = level;
-  return *this;
-}
 /* ----------------------------------------------------------------------- */
 // Inline methods for Errata::Data
 
@@ -779,16 +678,39 @@ inline Errata::Errata(self_type &&that) noexcept {
   std::swap(_data, that._data);
 }
 
-inline Errata::Errata(self_type const &that) {
-  if (nullptr != (_data = that._data)) {
-    ++(_data->_ref_count);
-  }
+inline Errata::Errata(const code_type &code, Severity severity) {
+  auto d = this->data();
+  d->_severity = severity;
+  d->_code = code;
+}
+
+inline Errata::Errata(const code_type &type, Severity severity, const 
std::string_view &text) : Errata(type, severity) {
+  this->note(text);
+}
+
+inline Errata::Errata(const std::string_view &text) : Errata(DEFAULT_CODE, 
DEFAULT_SEVERITY, text) {}
+inline Errata::Errata(code_type const& code, const std::string_view &text) : 
Errata(code, DEFAULT_SEVERITY, text) {}
+inline Errata::Errata(Severity severity, const std::string_view &text) : 
Errata(DEFAULT_CODE, severity, text) {}
+
+template <typename... Args> Errata::Errata(code_type const& code, Severity 
severity, std::string_view fmt, Args &&... args) : Errata(code, severity) {
+  this->note_v(fmt, std::forward_as_tuple(args...));
+}
+
+template <typename... Args> Errata::Errata(code_type const& type, 
std::string_view fmt, Args &&... args) : Errata(code, DEFAULT_SEVERITY, fmt, 
std::forward<Args>(args)...) { }
+template <typename... Args> Errata::Errata(Severity severity, std::string_view 
fmt, Args &&... args) : Errata(DEFAULT_CODE, severity, fmt, 
std::forward<Args>(args)...) { }
+template <typename... Args> Errata::Errata(std::string_view fmt, Args &&... 
args) : Errata(DEFAULT_CODE, DEFAULT_SEVERITY, fmt, 
std::forward<Args>(args)...) { }
+
+inline void Errata::reset() {
+  _data->~Data(); // destructs the @c MemArena in @a _data which releases 
memory.
+  _data = nullptr;
 }
 
 inline auto
 Errata::operator=(self_type &&that) -> self_type & {
   if (this != &that) {
-    this->release();
+    if (_data) {
+      this->reset();
+    }
     std::swap(_data, that._data);
   }
   return *this;
@@ -808,7 +730,7 @@ Errata::empty() const {
 }
 
 inline auto Errata::code() const -> code_type const& {
-  return this->empty() ? DEFAULT_CODE : _data->_notes.head()->_code;
+  return this->empty() ? DEFAULT_CODE : _data->_code;
 }
 
 inline size_t
@@ -840,37 +762,14 @@ Errata::note(self_type &&that) {
 
 inline Errata &
 Errata::note(std::string_view text) {
-  this->note_localized(DEFAULT_CODE, DEFAULT_SEVERITY, text);
+  this->note_localized(text);
   return *this;
 }
 
-inline Errata &
-Errata::note(Severity severity, std::string_view text) {
-  this->note_localized(DEFAULT_CODE, severity, text);
-  return *this;
-}
-
-inline Errata &
-Errata::note(code_type const& code, std::string_view text) {
-  this->note_localized(code, DEFAULT_SEVERITY, text);
-  return *this;
-}
-
-inline Errata &
-Errata::note(code_type const& code, Severity severity, std::string_view text) {
-  this->note_localized(code, severity, text);
-  return *this;
-}
-
-inline Errata &
-Errata::note(code_type const& code) {
-  return this->note(code, DEFAULT_SEVERITY);
-}
-
 template <typename... Args>
 Errata &
-Errata::note_v(code_type const& code, Severity severity, std::string_view fmt, 
std::tuple<Args...> const &args) {
-  Data *data = this->writeable_data();
+Errata::note_v(std::string_view fmt, std::tuple<Args...> const &args) {
+  Data *data = this->data();
   auto span  = data->remnant();
   FixedBufferWriter bw{span};
   if (!bw.print_v(fmt, args).error()) {
@@ -881,50 +780,39 @@ Errata::note_v(code_type const& code, Severity severity, 
std::string_view fmt, s
     span = this->alloc(bw.extent());
     FixedBufferWriter{span}.print_v(fmt, args);
   }
-  this->note_localized(code, severity, span.view());
+  this->note_localized(span.view());
   return *this;
 }
 
 template <typename... Args>
 Errata &
 Errata::note(std::string_view fmt, Args &&... args) {
-  return this->note_v(DEFAULT_CODE, DEFAULT_SEVERITY, fmt, 
std::forward_as_tuple(args...));
+  return this->note_v(fmt, std::forward_as_tuple<Args...>(args...));
 }
 
-template <typename... Args>
-Errata &
-Errata::note(Severity severity, std::string_view fmt, Args &&... args) {
-  return this->note_v(DEFAULT_CODE, severity, fmt, 
std::forward_as_tuple(args...));
+inline auto
+Errata::severity() const -> Severity {
+  return _data ? _data->_severity : DEFAULT_SEVERITY;
 }
 
-template <typename... Args>
-Errata &
-Errata::note(code_type const& code, std::string_view fmt, Args &&... args) {
-  return this->note_v(code, DEFAULT_SEVERITY, fmt, 
std::forward_as_tuple(args...));
+inline Errata::iterator
+Errata::begin() {
+  return _data ? _data->_notes.begin() : iterator();
 }
 
-template <typename... Args>
-Errata &
-Errata::note(code_type const& code, Severity severity, std::string_view fmt, 
Args &&... args) {
-  return this->note_v(code, severity, fmt, std::forward_as_tuple(args...));
+inline Errata::const_iterator
+Errata::begin() const {
+  return _data ? _data->_notes.begin() : const_iterator();
 }
 
-template <typename... Args>
-Errata &
-Errata::note_v(std::string_view fmt, std::tuple<Args...> const &args) {
-  return note_v(DEFAULT_CODE, DEFAULT_SEVERITY, fmt, args);
+inline Errata::iterator
+Errata::end() {
+  return _data ? _data->_notes.end() : iterator();
 }
 
-template <typename... Args>
-Errata &
-Errata::note_v(code_type const& code, std::string_view fmt, 
std::tuple<Args...> const &args) {
-  return note_v(code, DEFAULT_SEVERITY, fmt, args);
-}
-
-template <typename... Args>
-Errata &
-Errata::note_v(Severity severity, std::string_view fmt, std::tuple<Args...> 
const &args) {
-  return note_v(DEFAULT_CODE, severity, fmt, args);
+inline Errata::const_iterator
+Errata::end() const {
+  return _data ? _data->_notes.end() : const_iterator();
 }
 
 inline void
@@ -934,14 +822,31 @@ Errata::SinkWrapper::operator()(Errata const &e) const {
 /* ----------------------------------------------------------------------- */
 // Inline methods for Rv
 
+template < typename R > inline auto Rv<R>::note(std::string_view text) -> 
self_type & {
+  _errata.note(text);
+  return *this;
+}
+
+template < typename R > auto Rv<R>::note(const code_type &code) -> self_type & 
{
+  _errata.note(code);
+  return *this;
+}
+
 template <typename R>
-inline bool
+template<typename... Args> auto Rv<R>::note(std::string_view fmt, Args &&... 
args) -> self_type & {
+  _errata.note(fmt, std::forward<Args>(args)...);
+  return *this;
+}
+
+
+template <typename R>
+bool
 Rv<R>::is_ok() const {
   return _errata.is_ok();
 }
 
 template <typename R>
-inline auto
+auto
 Rv<R>::clear() -> self_type & {
   errata().clear();
   return *this;
@@ -1012,21 +917,6 @@ Rv<R>::operator=(Errata &&errata) -> self_type & {
   return *this;
 }
 
-template <typename R>
-auto
-Rv<R>::note(Severity severity, std::string_view text) -> self_type & {
-  _errata.note(severity, text);
-  return *this;
-}
-
-template <typename R>
-template <typename... Args>
-Rv<R> &
-Rv<R>::note(Severity level, std::string_view fmt, Args &&... args) {
-  _errata.note_v(level, fmt, std::forward_as_tuple(args...));
-  return *this;
-}
-
 template <typename R>
 inline Rv<R> &
 Rv<R>::note(Errata const &that) {
diff --git a/code/src/Errata.cc b/code/src/Errata.cc
index 82f5936..433c982 100644
--- a/code/src/Errata.cc
+++ b/code/src/Errata.cc
@@ -43,98 +43,51 @@ Errata::Data::localize(string_view src) {
 
 Errata::Severity Errata::DEFAULT_SEVERITY(1);
 Errata::Severity Errata::FAILURE_SEVERITY(1);
+swoc::MemSpan<TextView> Errata::SEVERITY_NAME;
 
 Errata::~Errata() {
-  this->release();
-}
-
-Errata&
-Errata::note(code_type const& code, Severity severity){
-  return this->note(code, severity, "{}", code);
-}
-
-void
-Errata::release() {
   if (_data) {
-    if (--(_data->_ref_count) == 0) {
-      if (!_data->empty()) {
-        for (auto& f : Sink_List) {
-          (*f)(*this);
-        }
+    if (!_data->empty()) {
+      for (auto &f : Sink_List) {
+        (*f)(*this);
       }
-      _data->~Data();
     }
-    _data = nullptr;
+    this->reset();
   }
 }
 
-const Errata::Data *
+Errata&
+Errata::note(code_type const& code){
+  return this->note("{}"_sv, code);
+}
+
+Errata::Data *
 Errata::data() {
   if (!_data) {
     MemArena arena{512};
     _data = arena.make<Data>(std::move(arena));
-    ++(_data->_ref_count);
   }
   return _data;
 }
 
-Errata::Data *
-Errata::writeable_data() {
-  if (!_data) {
-    this->data(); // force data existence, must be unique.
-  } else if (_data->_ref_count > 1) {
-    // Pondering this, there's really no good use case for shared write access 
to an Errata.
-    // The shared_ptr is used only to make function returns efficient. 
Explicit copying is
-    // easy using @c note.
-    throw std::runtime_error("Shared write to Errata");
-  };
-  return _data;
-}
-
-Errata::iterator
-Errata::begin() {
-  return _data ? _data->_notes.begin() : iterator();
-}
-
-Errata::const_iterator
-Errata::begin() const {
-  return _data ? _data->_notes.begin() : const_iterator();
-}
-
-Errata::iterator
-Errata::end() {
-  return _data ? _data->_notes.end() : iterator();
-}
-
-Errata::const_iterator
-Errata::end() const {
-  return _data ? _data->_notes.end() : const_iterator();
-}
-
-auto
-Errata::severity() const -> Severity {
-  return _data ? _data->_severity : DEFAULT_SEVERITY;
-}
-
 Errata&
-Errata::note_localized(code_type const& code, Severity severity, 
std::string_view const& text) {
-  auto d = this->writeable_data();
-  Annotation *n = d->_arena.make<Annotation>(code, severity, text);
+Errata::note_localized(std::string_view const& text) {
+  auto d = this->data();
+  Annotation *n = d->_arena.make<Annotation>(text);
   n->_level = d->_level;
   d->_notes.prepend(n);
-  _data->_severity = std::max(_data->_severity, severity);
   return *this;
 }
 
 MemSpan<char>
 Errata::alloc(size_t n) {
-  return this->writeable_data()->_arena.alloc(n).rebind<char>();
+  return this->data()->_arena.alloc(n).rebind<char>();
 }
 
 Errata&
 Errata::note(const self_type& that) {
   for (auto const& m : that) {
-    this->note(m._severity, m._text);
+    this->note(m._text);
   }
   return *this;
 }
@@ -142,8 +95,7 @@ Errata::note(const self_type& that) {
 Errata&
 Errata::clear() {
   if (_data) {
-    _data->_notes.clear(); // Prevent sink processing.
-    this->release();
+    _data->_notes.clear();
   }
   return *this;
 }
@@ -157,7 +109,7 @@ std::ostream&
 Errata::write(std::ostream& out) const {
   string_view lead;
   for (auto& m : *this) {
-    out << lead << " [" << static_cast<int>(m._severity) << "]: " << m._text 
<< std::endl;
+    out << lead << m._text << std::endl;
     if (0 == lead.size()) {
       lead = "  "_sv;
     }
@@ -167,15 +119,26 @@ Errata::write(std::ostream& out) const {
 
 BufferWriter&
 bwformat(BufferWriter& bw, bwf::Spec const& spec, Errata::Severity level) {
-  static constexpr std::string_view name[9] = {"DIAG", "DEBUG", "INFO", 
"NOTE", "WARNING", "ERROR"
-                                              , "FATAL", "ALERT", "EMERGENCY"};
-  return bwformat(bw, spec, name[static_cast<int>(level)]);
+  if (level < Errata::SEVERITY_NAME.size()) {
+    bwformat(bw, spec, Errata::SEVERITY_NAME[level]);
+  } else {
+    bwformat(bw, spec, level._raw);
+  }
+  return bw;
 }
 
 BufferWriter&
 bwformat(BufferWriter& bw, bwf::Spec const&, Errata const& errata) {
+
+  bw.print("{} ", errata.severity());
+
+  if (errata.code()) {
+    bw.print("[{0:s} {0:d}] ", errata.code());
+  }
+
+
   for (auto& m : errata) {
-    bw.print("{}[{}] {}\n", swoc::bwf::Pattern{int(m.level()), "  "}, 
m.severity(), m.text());
+    bw.print("{}{}\n", swoc::bwf::Pattern{int(m.level()), "  "}, m.text());
   }
   return bw;
 }
diff --git a/code/src/bw_format.cc b/code/src/bw_format.cc
index 35b01b8..a12a358 100644
--- a/code/src/bw_format.cc
+++ b/code/src/bw_format.cc
@@ -18,6 +18,7 @@
 #include "swoc/bwf_base.h"
 #include "swoc/bwf_ex.h"
 #include "swoc/swoc_meta.h"
+#include "swoc/DiscreteRange.h"
 
 using namespace std::literals;
 using namespace swoc::literals;
@@ -678,17 +679,154 @@ FixedBufferWriter::operator>>(std::ostream& s) const {
   return s << this->view();
 }
 
+namespace
+{
+// Hand rolled, might not be totally compliant everywhere, but probably close
+// enough. The long string will be locally accurate. Clang requires the double
+// braces. Why, Turing only knows.
+  static const std::array<std::string_view, 134> ERRNO_SHORT_NAME = {{
+    "SUCCESS",
+    "EPERM",
+    "ENOENT",
+    "ESRCH",
+    "EINTR",
+    "EIO",
+    "ENXIO",
+    "E2BIG ",
+    "ENOEXEC",
+    "EBADF",
+    "ECHILD",
+    "EAGAIN",
+    "ENOMEM",
+    "EACCES",
+    "EFAULT",
+    "ENOTBLK",
+    "EBUSY",
+    "EEXIST",
+    "EXDEV",
+    "ENODEV",
+    "ENOTDIR",
+    "EISDIR",
+    "EINVAL",
+    "ENFILE",
+    "EMFILE",
+    "ENOTTY",
+    "ETXTBSY",
+    "EFBIG",
+    "ENOSPC",
+    "ESPIPE",
+    "EROFS",
+    "EMLINK",
+    "EPIPE",
+    "EDOM",
+    "ERANGE",
+    "EDEADLK",
+    "ENAMETOOLONG",
+    "ENOLCK",
+    "ENOSYS",
+    "ENOTEMPTY",
+    "ELOOP",
+    "EWOULDBLOCK",
+    "ENOMSG",
+    "EIDRM",
+    "ECHRNG",
+    "EL2NSYNC",
+    "EL3HLT",
+    "EL3RST",
+    "ELNRNG",
+    "EUNATCH",
+    "ENOCSI",
+    "EL2HTL",
+    "EBADE",
+    "EBADR",
+    "EXFULL",
+    "ENOANO",
+    "EBADRQC",
+    "EBADSLT",
+    "EDEADLOCK",
+    "EBFONT",
+    "ENOSTR",
+    "ENODATA",
+    "ETIME",
+    "ENOSR",
+    "ENONET",
+    "ENOPKG",
+    "EREMOTE",
+    "ENOLINK",
+    "EADV",
+    "ESRMNT",
+    "ECOMM",
+    "EPROTO",
+    "EMULTIHOP",
+    "EDOTDOT",
+    "EBADMSG",
+    "EOVERFLOW",
+    "ENOTUNIQ",
+    "EBADFD",
+    "EREMCHG",
+    "ELIBACC",
+    "ELIBBAD",
+    "ELIBSCN",
+    "ELIBMAX",
+    "ELIBEXEC",
+    "EILSEQ",
+    "ERESTART",
+    "ESTRPIPE",
+    "EUSERS",
+    "ENOTSOCK",
+    "EDESTADDRREQ",
+    "EMSGSIZE",
+    "EPROTOTYPE",
+    "ENOPROTOOPT",
+    "EPROTONOSUPPORT",
+    "ESOCKTNOSUPPORT",
+    "EOPNOTSUPP",
+    "EPFNOSUPPORT",
+    "EAFNOSUPPORT",
+    "EADDRINUSE",
+    "EADDRNOTAVAIL",
+    "ENETDOWN",
+    "ENETUNREACH",
+    "ENETRESET",
+    "ECONNABORTED",
+    "ECONNRESET",
+    "ENOBUFS",
+    "EISCONN",
+    "ENOTCONN",
+    "ESHUTDOWN",
+    "ETOOMANYREFS",
+    "ETIMEDOUT",
+    "ECONNREFUSED",
+    "EHOSTDOWN",
+    "EHOSTUNREACH",
+    "EALREADY",
+    "EINPROGRESS",
+    "ESTALE",
+    "EUCLEAN",
+    "ENOTNAM",
+    "ENAVAIL",
+    "EISNAM",
+    "EREMOTEIO",
+    "EDQUOT",
+    "ENOMEDIUM",
+    "EMEDIUMTYPE",
+    "ECANCELED",
+    "ENOKEY",
+    "EKEYEXPIRED",
+    "EKEYREVOKED",
+    "EKEYREJECTED",
+    "EOWNERDEAD",
+    "ENOTRECOVERABLE",
+    "ERFKILL",
+    "EHWPOISON",
+  }};
+  static constexpr DiscreteRange<unsigned> ERRNO_RANGE{0, 
ERRNO_SHORT_NAME.size()-1 };
+  // This provides convenient safe access to the errno short name array.
+  auto errno_short_name = [](unsigned n) { return ERRNO_RANGE.contains(n) ? 
ERRNO_SHORT_NAME[n] : "Unknown"sv; };
+}
+
 BufferWriter&
 bwformat(BufferWriter& w, bwf::Spec const& spec, bwf::Errno const& e) {
-  // Hand rolled, might not be totally compliant everywhere, but probably close
-  // enough. The long string will be locally accurate. Clang requires the 
double
-  // braces. Why, Turing only knows.
-  static const std::array<std::string_view, 134> SHORT_NAME = {{
-                                                                   "SUCCESS", 
"EPERM", "ENOENT", "ESRCH", "EINTR", "EIO", "ENXIO", "E2BIG ", "ENOEXEC", 
"EBADF", "ECHILD", "EAGAIN", "ENOMEM", "EACCES", "EFAULT", "ENOTBLK", "EBUSY", 
"EEXIST", "EXDEV", "ENODEV", "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", 
"ENOTTY", "ETXTBSY", "EFBIG", "ENOSPC", "ESPIPE", "EROFS", "EMLINK", "EPIPE", 
"EDOM", "ERANGE", "EDEADLK", "ENAMETOOLONG", "ENOLCK", "ENOSYS", "ENOTEMPTY", 
"ELOOP", "EWOULDBLOCK", " [...]
-  // This provides convenient safe access to the errno short name array.
-  auto short_name = [](int n) {
-    return 0 < n && n < int(SHORT_NAME.size()) ? SHORT_NAME[n] : "Unknown"sv;
-  };
   static const bwf::Format number_fmt{"[{}]"sv}; // numeric value format.
 
   if (spec.has_numeric_type()) {                 // if numeric type, print 
just the numeric part
@@ -697,7 +835,7 @@ bwformat(BufferWriter& w, bwf::Spec const& spec, bwf::Errno 
const& e) {
     TextView ext { spec._ext };
     bool short_p = false;
     if (ext.empty() || ext.npos != ext.find('s')) {
-      w.write(short_name(e._e));
+      w.write(errno_short_name(e._e));
       short_p = true;
     }
     if (ext.empty() || ext.npos != ext.find('l')) {
@@ -838,13 +976,21 @@ operator<<(ostream &s, swoc::FixedBufferWriter &w)
 swoc::BufferWriter &
 bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, error_code const 
&ec)
 {
+  static const auto GENERIC_CATEGORY = &std::generic_category();
+  static const auto SYSTEM_CATEGORY = &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.
-  if (spec.has_numeric_type()) {                        // if numeric type, 
print just the numeric
-    // part.
-    w.print(number_fmt, ec.value());
+  if (spec.has_numeric_type()) {
+    // if numeric type, print just the numeric part.
+    bwformat(w, spec, ec.value());
   } else {
-    w.write(ec.message());
+    if ((&ec.category() == GENERIC_CATEGORY || &ec.category() == 
SYSTEM_CATEGORY) &&
+        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());
diff --git a/doc/code/Errata.en.rst b/doc/code/Errata.en.rst
index 99986ee..8d65c8b 100644
--- a/doc/code/Errata.en.rst
+++ b/doc/code/Errata.en.rst
@@ -17,6 +17,7 @@
 .. highlight:: cpp
 .. default-domain:: cpp
 .. |Errata| replace:: :code:`Errata`
+.. |Rv| replace:: :code:`Rv`
 
 ******
 Errata
@@ -27,10 +28,9 @@ Errata
 *  Very fast in the success case.
 *  Easy to accumulate error messages in a failure case.
 
-An assumption is that error handling is always intrisincally expensive, in 
particular if errors are
-reported or logged, therefore in the error case it is better to be 
comprehensive and easy to use.
-Conversely, the success case should be optimized for performance as in it is 
all overhead in that
-case.
+An assumption is that error handling is always intrinsically expensive, in 
particular if errors are
+reported or logged therefore in the error case it is better to be 
comprehensive and easy to use.
+Conversely, the success case should be optimized for performance because it is 
all overhead.
 
 If errors are to be reported, they should be as detailed as possible. |Errata| 
supports by allowing
 error messages to accumulate. This means detailed error reports do not require 
passing large amounts
@@ -44,60 +44,127 @@ file parser, can report it was the configuration file open 
that failed.
 Definition
 **********
 
+.. code-block::
+
+   #include <swoc/Errata.h>
+
 .. class:: Errata
 
    :libswoc:`Reference documentation <Errata>`.
 
-   .. function:: Errata & note(Severity level, std::string_view text)
+Usage
+*****
 
-      Add a message to this instance.
+The default |Errata| constructor creates an empty, successful state. An error 
state is created
+constructing an instance with an annotation and optional error code and 
severity.
 
-   .. class:: Annotation
+The basic interface is provided by the :func:`Errata::note` method. This adds 
a message along with a
+severity. Using |Errata| requires defining the default severity and "failure" 
severity. The default
+severity is simply what is used if no severity is provided. The failure 
severity is the severity for
+which an |Errata| is considered to be an error.
 
-      :libswoc:`Reference documentation <Errata::Annotation>`.
+An |Errata| instance also carries a message identifier which is intended to 
distinguish among
+errors of the same sererity in an easy to examine way. For this reason 
:code:`std::error_code`
+is used as the identifier. This allows constructing an instance from the error 
return of system
+functions and for callers to check if the error is really an error. Note, 
however, that severity
+and the message identifier are independent.
 
-.. enum:: Severity
+|Errata| provides the :libswoc:`Rv` template which is intended for passing 
back return values or
+error reports. The template parameter is the return type, to which is added an 
|Errata| instance.
+The |Rv| instance implicitly converts to the return type so that if a function 
is changed from
+returning :code:`T` to :code:`Rv<T>` the callers do not need to be changed.
 
-   :libswoc:`Reference documentation <Severity>`.
+Severity
+========
 
-   This is an error severity level, based as always on the `syslog levels
-   <http://man7.org/linux/man-pages/man3/syslog.3.html>`__. Currently a subset 
of those are
-   supported.
+The severity support has been a bit of an issue. Although the support seems a 
bit convoluted, in
+practice users of |Errata| tend to have an already defined severity scale. The 
goal is to be able
+to integrate that existing scale easily in to |Errata|.
 
-   .. enumerator:: DIAG
+For the purposes of the unit testing and example code the following is 
included to define the
+severity levels. This is modeled as usual on the ``syslog`` severity levels.
 
-      Internal diagnostics, essentially for debugging and verbose information. 
The lowest severity.
+.. code-block::
 
-   .. enumerator:: INFO
+   static constexpr swoc::Errata::Severity ERRATA_DBG{0};
+   static constexpr swoc::Errata::Severity ERRATA_DIAG{1};
+   static constexpr swoc::Errata::Severity ERRATA_INFO{2};
+   static constexpr swoc::Errata::Severity ERRATA_WARN{3};
+   static constexpr swoc::Errata::Severity ERRATA_ERROR{4};
 
-      Information messages intended for end users, in contrast to 
:cpp:enumerator:`DIAG`
-      which is for developers.
+It is expected the application would already have the equivalent definitions 
and would not need any
+special ones for |Errata|. The severity values are initialized during start up.
 
-   .. enumerator:: WARN
+.. code-block::
 
-      A warning, which indicates a failure or error that is recoverable but 
should be addressed.
+   int main(int argc, char *argv[]) {
+     // other initialization
+     swoc::Errata::DEFAULT_SEVERITY = ERRATA_ERROR;
+     swoc::Errata::FAILURE_SEVERITY = ERRATA_WARN;
+     // ... more code
 
-   .. enumerator:: ERROR
+Examples
+========
 
-      A error that prevents further action.
+There are two fundamental cases for use of |Errata|. The first is the leaf 
function that creates
+the original |Errata| instance. The other case is code which calls an |Errata| 
returning function.
+Loading a configuration file will be used as an example.
 
-Usage
-*****
+A leaf function could be one that, given a path, opens the file and loads it 
in to a :code:`std::string`
+using :libswoc:`file::load`.
 
-The default |Errata| constructor creates an empty, successful state. An error 
state is created
-by adding :class:`Errata::Annotation`\s to the instance. This can be done in a 
number of ways.
+.. code-block::
 
-The basic interface is provided by the :func:`Errata::note` method. This adds 
a message along with
-a severity for the message. An instance is considered an error
+   Errata load_file(swoc::path const& path) {
+      std::error_code ec;
+      std::string content = swoc::file::load(path, ec);
+      if (ec) {
+         return Errata(ec, ERRATA_ERROR, "Failed to open file {}.", path);
+      }
+      // config parsing logic
+   }
+
+The call site might look like
+
+.. code-block::
+
+   Errata load_config(swoc::path const& path) {
+      if (Errata errata = this->load_file(path) ; ! errata.is_ok()) {
+         return std::move(errata.note("While opening configuration file."));
+      }
+      // ... more code.
 
-Examples
-========
 
 Design Notes
 ************
 
-I have carted around variants of this class for almost two decades, the 
evolution being driver
+I have carted around variants of this class for almost two decades, the 
evolution being driven
 primarily by the evolving capabilities of C++ rather than a fundamental change 
in the design
 philosophy. The original impetus was as noted in the introduction, to be able 
to generate a
 very detailed and thorough error report on a failure, which as much context as 
possible. In some
 sense, to have a stack trace without actually crashing.
+
+Recently (Sep 2021) I've restructured |Errata| based on additional usage 
experience.
+
+*  The error code was removed for a while but has been added back. Although 
not that common, it is
+   not rare that having a code is useful for determining behavior for an 
error. The most common
+   example is :code:`EAGAIN` and equivalent - the caller might well want to 
log and try again rather
+   than immediately fail. To be most useful the error code was made to be 
:code:`std::error_code`
+   which covers both C++ error codes and standard "errno" errors.
+
+*  The error code and severity was moved from messages to the |Errata| 
instance. The internals were
+   already promoting the highest severity of the messages to be the overall 
severity, and error codes
+   for messages other than the front message seemed useless. In practice the 
only use of having this
+   in the message was to have something to set on a default constructed 
|Errata|. Overall it seems
+   cleaner to have more |Errata| constructors to construct that initial 
message with the error code
+   and severity and not have it when adding new messages (because, what 
severity should be used in
+   such cases? - it's really not clear).
+
+*  The reference counting was removed. With the advent of move semantics there 
is much less need
+   to make cheap copies with copy on write support. The change from general 
memory allocation to
+   use of an internal `MemArena` it is no longer possible to share messages 
between instances which
+   makes the copy on write use of the reference count useless. For these two 
reasons reference was
+   removed along with any copying. Use must either explicitly copy via the 
:code:`note` method or
+   "move" the value, which intermediate functions must now use. I think this 
is worth that cost
+   because there are edge cases that are hard to handle with reference 
counting which don't arise
+   with pure move semantics.
diff --git a/doc/index.rst b/doc/index.rst
index 67e7147..d9036f7 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -39,6 +39,7 @@ unrelated projects. Hence this library. I hope you find it as 
useful as I have.
    code/Errata.en
    code/Scalar.en
    code/IPSpace.en
+   appendix.en
 
 Indices and tables
 ******************
diff --git a/unit_tests/ex_Errata_Severity.h b/unit_tests/ex_Errata_Severity.h
index e9328e0..1e7d5e2 100644
--- a/unit_tests/ex_Errata_Severity.h
+++ b/unit_tests/ex_Errata_Severity.h
@@ -26,23 +26,3 @@ static constexpr swoc::Errata::Severity ERRATA_DIAG{1};
 static constexpr swoc::Errata::Severity ERRATA_INFO{2};
 static constexpr swoc::Errata::Severity ERRATA_WARN{3};
 static constexpr swoc::Errata::Severity ERRATA_ERROR{4};
-
-inline swoc::Errata & Dbg(swoc::Errata & erratum, std::string_view text) {
-  return erratum.note(ERRATA_DBG, text);
-}
-
-inline swoc::Errata & Diag(swoc::Errata & erratum, std::string_view text) {
-  return erratum.note(ERRATA_DIAG, text);
-}
-
-inline swoc::Errata & Info(swoc::Errata & erratum, std::string_view text) {
-  return erratum.note(ERRATA_INFO, text);
-}
-
-inline swoc::Errata & Warn(swoc::Errata & erratum, std::string_view text) {
-  return erratum.note(ERRATA_WARN, text);
-}
-
-inline swoc::Errata & Error(swoc::Errata & erratum, std::string_view text) {
-  return erratum.note(ERRATA_ERROR, text);
-}
diff --git a/unit_tests/ex_UnitParser.cc b/unit_tests/ex_UnitParser.cc
index 06f8d0f..fc80a0b 100644
--- a/unit_tests/ex_UnitParser.cc
+++ b/unit_tests/ex_UnitParser.cc
@@ -18,15 +18,6 @@ using swoc::Lexicon;
 using swoc::Errata;
 using swoc::Rv;
 
-namespace {
-
-// Shortcut for creating an @c Errata with a single error message.
-template < typename ... Args > Errata Error(TextView const& fmt, Args && ... 
args) {
-  return Errata{}.note_v(ERRATA_ERROR, fmt, std::forward_as_tuple(args...));
-}
-
-} // namespace
-
 /** Parse a string that consists of counts and units.
  *
  * Give a set of units, each of which is a list of names and a multiplier, 
parse a string. The
@@ -91,7 +82,7 @@ auto UnitParser::operator()(swoc::TextView const& src) const 
noexcept -> Rv<valu
     auto ptr = text.data(); // save for error reporting.
     auto count = text.clip_prefix_of(&isdigit);
     if (count.empty()) {
-      return { 0 , Error("Required count not found at offset {}", ptr - 
src.data()) };
+      return Errata("Required count not found at offset {}", ptr - src.data());
     }
     // Should always parse correctly as @a count is a non-empty sequence of 
digits.
     auto n = svtou(count);
@@ -102,13 +93,13 @@ auto UnitParser::operator()(swoc::TextView const& src) 
const noexcept -> Rv<valu
     auto unit = text.clip_prefix_of([](char c) { return !(isspace(c) || 
isdigit(c)); } );
     if (unit.empty()) {
       if (_unit_required_p) {
-        return { 0, Error("Required unit not found at offset {}", ptr - 
src.data()) };
+        return Errata("Required unit not found at offset {}", ptr - 
src.data());
       }
       zret += n; // no metric -> unit metric.
     } else {
       auto mult = _units[unit]; // What's the multiplier?
       if (mult == 0) {
-        return {0, Error("Unknown unit \"{}\" at offset {}", unit, ptr - 
src.data())};
+        return Errata("Unknown unit \"{}\" at offset {}", unit, ptr - 
src.data());
       }
       zret += mult * n;
     }
diff --git a/unit_tests/test_Errata.cc b/unit_tests/test_Errata.cc
index a01d30e..47e2ce5 100644
--- a/unit_tests/test_Errata.cc
+++ b/unit_tests/test_Errata.cc
@@ -1,25 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
 /** @file
 
     Errata unit tests.
-
-    @section license License
-
-    Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
-    agreements.  See the NOTICE file distributed with this work for additional 
information regarding
-    copyright ownership.  The ASF licenses this file to you under the Apache 
License, Version 2.0
-    (the "License"); you may not use this file except in compliance with the 
License.  You may
-    obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software 
distributed under the
-    License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY KIND, either
-    express or implied. See the License for the specific language governing 
permissions and
-    limitations under the License.
 */
 
 #include <memory>
+#include <errno.h>
 #include "swoc/Errata.h"
+#include "swoc/swoc_file.h"
 #include "ex_Errata_Severity.h"
 #include "catch.hpp"
 
@@ -27,20 +15,20 @@ using swoc::Errata;
 using swoc::Rv;
 using Severity = swoc::Errata::Severity;
 using namespace std::literals;
+using namespace swoc::literals;
+
+// Note - Some of these tests depend on initialization done in 
"unit_test_main.cc".
 
 Errata
 Noteworthy(std::string_view text)
 {
-  Errata notes;
-  Info(notes, text);
-  return notes;
+  return Errata{ERRATA_INFO, text};
 }
 
 Errata
 cycle(Errata &erratum)
 {
-  Info(erratum, "Note well, young one!");
-  return erratum;
+  return std::move(erratum.note("Note well, young one!"));
 }
 
 TEST_CASE("Errata copy", "[libswoc][Errata]")
@@ -53,22 +41,17 @@ TEST_CASE("Errata copy", "[libswoc][Errata]")
   REQUIRE(notes.length() == 2);
 
   Errata erratum;
-  erratum.clear();
   REQUIRE(erratum.length() == 0);
-  Diag(erratum, "Diagnostics");
+  erratum.note("Diagnostics");
   REQUIRE(erratum.length() == 1);
-  Info(erratum, "Information");
+  erratum.note("Information");
   REQUIRE(erratum.length() == 2);
-  Warn(erratum, "Warning");
-  REQUIRE(erratum.length() == 3);
-  Error(erratum, "Error");
-  REQUIRE(erratum.length() == 4);
 
   // Test internal allocation boundaries.
   notes.clear();
   std::string_view text{"0123456789012345678901234567890123456789"};
   for (int i = 0; i < 50; ++i) {
-    Info(notes, text);
+    notes.note(text);
   }
   REQUIRE(notes.length() == 50);
   REQUIRE(notes.begin()->text() == text);
@@ -91,25 +74,29 @@ TEST_CASE("Rv", "[libswoc][Errata]")
   using ThingHandle = std::unique_ptr<Thing>;
 
   zret = 17;
-  zret.note(ERRATA_ERROR, "This is an error");
+  zret = Errata(std::error_code(EINVAL, std::generic_category()), 
ERRATA_ERROR, "This is an error");
 
-  auto [result, erratum] = zret;
+  {
+    auto & [result, erratum] = zret;
 
-  REQUIRE(erratum.length() == 1);
-  REQUIRE(erratum.severity() == ERRATA_ERROR);
+    REQUIRE(erratum.length() == 1);
+    REQUIRE(erratum.severity() == ERRATA_ERROR);
 
-  REQUIRE(result == 17);
-  zret = 38;
-  REQUIRE(result == 17); // Local copy binding, no update.
+    REQUIRE(result == 17);
+    zret = 38;
+    REQUIRE(result == 38); // reference binding, update.
+  }
 
-  auto &[r_result, r_erratum] = zret;
+  {
+    auto && [result, erratum] = zret;
 
-  REQUIRE(r_result == 38);
-  zret = 56;
-  REQUIRE(r_result == 56); // reference binding, update.
+    REQUIRE(erratum.length() == 1);
+    REQUIRE(erratum.severity() == ERRATA_ERROR);
 
-  auto const &[cr_result, cr_erratum] = zret;
-  REQUIRE(cr_result == 56);
+    REQUIRE(result == 38);
+    zret = 56;
+    REQUIRE(result == 56); // reference binding, update.
+  }
 
   auto test = [](Severity expected_severity, Rv<int> const &rvc) {
     auto const &[cv_result, cv_erratum] = rvc;
@@ -118,39 +105,55 @@ TEST_CASE("Rv", "[libswoc][Errata]")
     REQUIRE(cv_result == 56);
   };
 
-  test(ERRATA_ERROR, zret); // invoke it.
+  {
+    auto const &[result, erratum] = zret;
+    REQUIRE(result == 56);
+
+    test(ERRATA_ERROR, zret); // invoke it.
+  }
+
 
   zret.clear();
-  auto const &[cleared_result, cleared_erratum] = zret;
-  REQUIRE(cleared_result == 56);
-  REQUIRE(cleared_erratum.length() == 0);
-  Diag(zret, "Diagnostics");
+  REQUIRE(zret.result() == 56);
+
+  {
+    auto const &[result, erratum] = zret;
+    REQUIRE(result == 56);
+    REQUIRE(erratum.length() == 0);
+  }
+
+  zret.note("Diagnostics");
   REQUIRE(zret.errata().length() == 1);
-  Info(zret, "Information");
+  zret.note("Information");
   REQUIRE(zret.errata().length() == 2);
-  Warn(zret, "Warning");
+  zret.note("Warning");
   REQUIRE(zret.errata().length() == 3);
-  Error(zret, "Error");
+  zret.note("Error");
   REQUIRE(zret.errata().length() == 4);
   REQUIRE(zret.result() == 56);
 
-  test(ERRATA_DIAG, Rv<int>{56}.note(ERRATA_DIAG, "Test rvalue diag"));
-  test(ERRATA_INFO, Rv<int>{56}.note(ERRATA_INFO, "Test rvalue info"));
-  test(ERRATA_WARN, Rv<int>{56}.note(ERRATA_WARN, "Test rvalue warn"));
-  test(ERRATA_ERROR, Rv<int>{56}.note(ERRATA_ERROR, "Test rvalue error"));
+  test(ERRATA_DIAG, Rv<int>{56, Errata(ERRATA_DIAG, "Test rvalue diag")});
+  test(ERRATA_INFO, Rv<int>{56, Errata(ERRATA_INFO, "Test rvalue info")});
+  test(ERRATA_WARN, Rv<int>{56, Errata(ERRATA_WARN, "Test rvalue warn")});
+  test(ERRATA_ERROR, Rv<int>{56, Errata(ERRATA_ERROR, "Test rvalue error")});
 
   // Test the note overload that takes an Errata.
   zret.clear();
   REQUIRE(zret.result() == 56);
   REQUIRE(zret.errata().length() == 0);
-  Errata errata;
-  Info(errata, "Information");
-  zret.note(errata);
-  test(ERRATA_INFO, zret);
-  REQUIRE(errata.length() == 1);
-  zret.note(std::move(errata));
+  zret = Errata{ERRATA_INFO, "Information"};
+  REQUIRE(ERRATA_INFO == zret.errata().severity());
+  REQUIRE(zret.errata().length() == 1);
+
+  Errata e1{ERRATA_DBG, "Debug"};
+  zret.note(e1);
   REQUIRE(zret.errata().length() == 2);
-  REQUIRE(errata.length() == 0);
+  REQUIRE(ERRATA_INFO == zret.errata().severity());
+
+  Errata e2{ERRATA_DBG, "Debug"};
+  zret.note(std::move(e2));
+  REQUIRE(zret.errata().length() == 3);
+  REQUIRE(e2.length() == 0);
 
   // Now try it on a non-copyable object.
   ThingHandle handle{new Thing};
@@ -158,7 +161,7 @@ TEST_CASE("Rv", "[libswoc][Errata]")
 
   handle->s = "other"; // mark it.
   thing_rv  = std::move(handle);
-  thing_rv.note(ERRATA_WARN, "This is a warning");
+  thing_rv = Errata(ERRATA_WARN, "This is a warning");
 
   auto &&[tr1, te1]{thing_rv};
   REQUIRE(te1.length() == 1);
@@ -178,3 +181,16 @@ TEST_CASE("Rv", "[libswoc][Errata]")
   auto &&[tr2, te2]{maker()};
   REQUIRE(tr2->s == "made"sv);
 };
+
+TEST_CASE("Errata example", "[libswoc][Errata]") {
+  swoc::LocalBufferWriter<2048> w;
+  std::error_code ec;
+  swoc::file::path path("does-not-exist.txt");
+  auto content = swoc::file::load(path, ec);
+  REQUIRE(false == !ec); // it is expected the load will fail.
+  Errata errata{ec, ERRATA_ERROR, R"(Failed to open file "{}")", path};
+  w.print("{}", errata);
+  REQUIRE(w.size() > 0);
+  REQUIRE(w.view().starts_with("Error") == true);
+  REQUIRE(w.view().find("enoent") != swoc::TextView::npos);
+}
diff --git a/unit_tests/unit_test_main.cc b/unit_tests/unit_test_main.cc
index c16d4e1..5f87462 100644
--- a/unit_tests/unit_test_main.cc
+++ b/unit_tests/unit_test_main.cc
@@ -23,8 +23,14 @@
 #define CATCH_CONFIG_RUNNER
 #include "catch.hpp"
 
+#include <array>
+
 #include "ex_Errata_Severity.h"
 
+std::array<swoc::TextView, 5> Severity_Names { {
+  "Debug", "Diag", "Info", "Warn", "Error"
+}};
+
 void EX_BWF_Format_Init();
 
 int
@@ -34,6 +40,7 @@ main(int argc, char *argv[])
 
   swoc::Errata::DEFAULT_SEVERITY = ERRATA_ERROR;
   swoc::Errata::FAILURE_SEVERITY = ERRATA_WARN;
+  swoc::Errata::SEVERITY_NAME = 
swoc::MemSpan<swoc::TextView>(Severity_Names.data(), Severity_Names.size());
 
   int result = Catch::Session().run(argc, argv);
 

Reply via email to