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