You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2018/08/13 20:05:28 UTC

[trafficserver] 02/03: BufferWriter: Add OptionalAffix support for optionally printing strings. Update the documenation.

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

zwoop pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit c25f554a9c1c250305e48bd0fdc16cfd2ce1f22c
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Mon Jul 2 20:46:56 2018 -0500

    BufferWriter: Add OptionalAffix support for optionally printing strings.
    Update the documenation.
    
    (cherry picked from commit 59d1c368e94c7c3f2c1ccf44b69f65bdc3158f74)
---
 .../internal-libraries/buffer-writer.en.rst        | 92 ++++++++++++++++++----
 lib/ts/BufferWriterFormat.cc                       |  6 ++
 lib/ts/bwf_std_format.h                            | 25 ++++++
 3 files changed, 109 insertions(+), 14 deletions(-)

diff --git a/doc/developer-guide/internal-libraries/buffer-writer.en.rst b/doc/developer-guide/internal-libraries/buffer-writer.en.rst
index 4f7a416..adbf871 100644
--- a/doc/developer-guide/internal-libraries/buffer-writer.en.rst
+++ b/doc/developer-guide/internal-libraries/buffer-writer.en.rst
@@ -638,7 +638,9 @@ uses the :code:`std::string` overload for :func:`bwprint` would look like ::
    }
 
 This gathers the argument (generally references to the arguments) in to a single tuple which is then
-passed by reference, to avoid restacking the arguments for every nested function call.
+passed by reference, to avoid restacking the arguments for every nested function call. In essence the
+arguments are put on the stack (inside the tuple) once and a reference to that stack is passed to
+nested functions.
 
 Specialized Types
 -----------------
@@ -715,46 +717,108 @@ but can be overloaded to produce different (wrapper class based) output. The cla
 such as the descriptive string for the value. To do this the format wrapper class :code:`ts::bwf::Errno`
 is provided. Using it is simple::
 
-    w.print("File not open - {}", ts::bwf::Errno(errno));
+   w.print("File not open - {}", ts::bwf::Errno(errno));
 
 which will produce output that looks like
 
-    "File not open - EACCES: Permission denied [13]"
+   "File not open - EACCES: Permission denied [13]"
 
 For :code:`errno` this is handy in another way as :code:`ts::bwf::Errno` will preserve the value of
 :code:`errno` across other calls that might change it. E.g.::
 
-    ts::bwf::Errno last_err(errno);
-    // some other code generating diagnostics that might tweak errno.
-    w.print("File not open - {}", last_err);
+   ts::bwf::Errno last_err(errno);
+   // some other code generating diagnostics that might tweak errno.
+   w.print("File not open - {}", last_err);
+
+This can also be useful for user defined data types. For instance, in the HostDB the type of the entry
+is printed in multiple places and each time this code is repeated ::
+
+      "%s%s %s", r->round_robin ? "Round-Robin" : "",
+         r->reverse_dns ? "Reverse DNS" : "", r->is_srv ? "SRV" : "DNS"
+
+This could be wrapped in a class, :code:`HostDBType` such as ::
+
+   struct HostDBType {
+      HostDBInfo* _r { nullptr };
+      HostDBType(r) : _r(r) {}
+   };
+
+Then define a formatter for the wrapper ::
+
+   BufferWriter& bwformat(BufferWriter& w, BWFSpec const& spec, HostDBType const& wrap) {
+     return w.print("{}{} {}", wrap._r->round_robin ? "Round-Robin" : "",
+        r->reverse_dns ? "Reverse DNS" : "",
+        r->is_srv ? "SRV" : "DNS");
+   }
+
+Now this can be output elsewhere with just
+
+   w.print("{}", HostDBType(r));
+
+If this is used multiple places, this is cleaner and more robust as it can be updated everywhere with a
+change in a single code location.
 
 These are the existing format classes in header file ``bfw_std_format.h``. All are in the :code:`ts::bwf` namespace.
 
 .. class:: Errno
 
-    Formating for :code:`errno`.
+   Formating for :code:`errno`.
 
-    .. function:: Errno(int errno)
+   .. function:: Errno(int errno)
 
 .. class:: Date
 
-    Date formatting in the :code:`strftime` style.
+   Date formatting in the :code:`strftime` style.
 
-    .. function:: Date(time_t epoch, std::string_view fmt = "%Y %b %d %H:%M:%S")
+   .. function:: Date(time_t epoch, std::string_view fmt = "%Y %b %d %H:%M:%S")
 
-        :arg:`epoch` is the time to print. :arg:`fmt` is the format for printing which is identical to that of `strftime <https://linux.die.net/man/3/strftime>`__. The default format looks like "2018 Jun 08 13:55:37".
+      :arg:`epoch` is the time to print. :arg:`fmt` is the format for printing which is identical to
+      that of `strftime <https://linux.die.net/man/3/strftime>`__. The default format looks like
+      "2018 Jun 08 13:55:37".
 
-    .. function:: Date(std::string_view fmt = "%Y %b %d %H:%M:%S")
+   .. function:: Date(std::string_view fmt = "%Y %b %d %H:%M:%S")
 
-         As previous except the epoch is the current epoch at the time the constructor is invoked. Therefore if the current time is to be printed the default constructor can be used.
+      As previous except the epoch is the current epoch at the time the constructor is invoked.
+      Therefore if the current time is to be printed the default constructor can be used.
 
-   When used the format specification can take an extention of "local" which formats the time as local time. Otherwise it is GMT.
+   When used the format specification can take an extention of "local" which formats the time as
+   local time. Otherwise it is GMT.
    ``w.print("{}", Date("%H:%M"));`` will print the hour and minute as GMT values. ``w.print("{::local}", Date("%H:%M"));`` will
    When used the format specification can take an extention of "local" which formats the time as local time. Otherwise it is GMT.
    ``w.print("{}", Date("%H:%M"));`` will print the hour and minute as GMT values. ``w.print("{::local}", Date("%H:%M"));`` will
    print the hour and minute in the local time zone. ``w.print("{::gmt}"), ...);`` will output in GMT if additional explicitness is
    desired.
 
+.. class:: OptionalAffix
+
+   Affix support for printing optional strings. This enables printing a string such the affixes are printed only if the string is not
+   empty. An empty string (or :code:`nullptr`) yields no output. A common situation in which is this is useful is code like ::
+
+      printf("%s%s", data ? data : "", data ? " " : "");
+
+   or something like ::
+
+      if (data) {
+         printf("%s ", data);
+      }
+
+   Instead :class:`OptionalAffix` can be used in line, which is easier if there are multiple items. E.g.
+
+      w.print("{}", ts::bwf::OptionalAffix(data)); // because default is single trailing space suffix.
+
+   .. function:: OptionalAffix(const char* text, std::string_view suffix = " ", std::string_view prefix = "")
+
+      Create a format wrapper with :arg:`suffix` and :arg:`prefix`. If :arg:`text` is
+      :code:`nullptr` or is empty generate no output. Otherwise print the :arg:`prefix`,
+      :arg:`text`, :arg:`suffix`.
+
+   .. function:: OptionalAffix(std::string_view text, std::string_view suffix = " ", std::string_view prefix = "")
+
+      Create a format wrapper with :arg:`suffix` and :arg:`prefix`. If :arg:`text` is
+      :code:`nullptr` or is empty generate no output. Otherwise print the :arg:`prefix`,
+      :arg:`text`, :arg:`suffix`. Note that passing :code:`std::string` as the first argument will
+      work for this overload.
+
 Global Names
 ++++++++++++
 
diff --git a/lib/ts/BufferWriterFormat.cc b/lib/ts/BufferWriterFormat.cc
index e265276..836c972 100644
--- a/lib/ts/BufferWriterFormat.cc
+++ b/lib/ts/BufferWriterFormat.cc
@@ -951,6 +951,12 @@ bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Date const &date)
   return w;
 }
 
+BufferWriter &
+bwformat(BufferWriter &w, BWFSpec const &spec, bwf::OptionalAffix const &opts)
+{
+  return w.write(opts._prefix).write(opts._text).write(opts._suffix);
+}
+
 } // namespace ts
 
 namespace
diff --git a/lib/ts/bwf_std_format.h b/lib/ts/bwf_std_format.h
index aee70f6..d90da57 100644
--- a/lib/ts/bwf_std_format.h
+++ b/lib/ts/bwf_std_format.h
@@ -66,9 +66,34 @@ namespace bwf
     Date(std::string_view fmt = DEFAULT_FORMAT);
   };
 
+  /** For optional printing strings along with suffixes and prefixes.
+   *  If the wrapped string is null or empty, nothing is printed. Otherwise the prefix, string,
+   *  and suffix are printed. The default are a single space for suffix and nothing for the prefix.
+   */
+  struct OptionalAffix {
+    std::string_view _text;
+    std::string_view _suffix;
+    std::string_view _prefix;
+
+    OptionalAffix(const char *text, std::string_view suffix = " "sv, std::string_view prefix = ""sv)
+      : OptionalAffix(std::string_view(text ? text : ""), suffix, prefix)
+    {
+    }
+
+    OptionalAffix(std::string_view text, std::string_view suffix = " "sv, std::string_view prefix = ""sv)
+    {
+      // If text is null or empty, leave the members empty too.
+      if (!text.empty()) {
+        _text   = text;
+        _prefix = prefix;
+        _suffix = suffix;
+      }
+    }
+  };
 } // namespace bwf
 
 BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Errno const &e);
 BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Date const &date);
+BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::OptionalAffix const &opts);
 
 } // namespace ts