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 05a6883ccdc6963f6cdb2438e2d86a7f847684fe Author: Alan M. Carroll <a...@apache.org> AuthorDate: Wed Jun 6 14:59:28 2018 -0500 BWF: Add errno support. (cherry picked from commit 3d8ad11af446cffbc4ceb58a80b5604bdf391edb) --- .../internal-libraries/buffer-writer.en.rst | 24 ++++ lib/ts/BufferWriterFormat.cc | 160 +++++++++++++++++++++ lib/ts/bwf_std_format.h | 14 ++ lib/ts/unit-tests/test_BufferWriterFormat.cc | 10 ++ 4 files changed, 208 insertions(+) diff --git a/doc/developer-guide/internal-libraries/buffer-writer.en.rst b/doc/developer-guide/internal-libraries/buffer-writer.en.rst index f8f19df..ced90d4 100644 --- a/doc/developer-guide/internal-libraries/buffer-writer.en.rst +++ b/doc/developer-guide/internal-libraries/buffer-writer.en.rst @@ -704,6 +704,30 @@ These are types for which there exists a type specific BWF formatter. bw.print("{:>20: =a}",addr); // -> " 172. 19. 3.105" } +Format Classes +++++++++++++++ + +Although the extension for a format can be overloaded to provide additional features, this can become +too confusing and complex to use if it is used for fundamentally different semantics on the same +based type. In that case it is better to provide a format wrapper class that holds the base type +but can be overloaded to produce different (wrapper class based) output. The classic example is +:code:`errno` which is an integral type but frequently should be formatted with additional information +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)); + +which will produce output that looks like + + "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); + Global Names ++++++++++++ diff --git a/lib/ts/BufferWriterFormat.cc b/lib/ts/BufferWriterFormat.cc index 4bdd507..18384c9 100644 --- a/lib/ts/BufferWriterFormat.cc +++ b/lib/ts/BufferWriterFormat.cc @@ -22,6 +22,7 @@ */ #include <ts/BufferWriter.h> +#include <ts/bwf_std_format.h> #include <unistd.h> #include <sys/param.h> #include <cctype> @@ -755,6 +756,164 @@ bwf_register_global(std::string_view name, BWGlobalNameSignature formatter) return ts::bw_fmt::BWF_GLOBAL_TABLE.emplace(name, formatter).second; } +BufferWriter & +bwformat(BufferWriter &w, BWFSpec 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: ", + "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: ", + }}; + // This provides convenient safe access to the errno short name array. + auto short_name = [](int n) { return n < static_cast<int>(SHORT_NAME.size()) ? SHORT_NAME[n] : "Unknown: "sv; }; + static const BWFormat number_fmt{"[{}]"sv}; // numeric value format. + if (spec.has_numeric_type()) { // if numeric type, print just the numeric part. + w.print(number_fmt, e._e); + } else { + w.write(short_name(e._e)); + w.write(strerror(e._e)); + if (spec._type != 's' && spec._type != 'S') { + w.write(' '); + w.print(number_fmt, e._e); + } + } + return w; +} + } // namespace ts namespace @@ -808,6 +967,7 @@ static bool BW_INITIALIZED __attribute__((unused)) = []() -> bool { ts::bw_fmt::BWF_GLOBAL_TABLE.emplace("thread-name", &BWF_ThreadName); return true; }(); + } // namespace namespace std diff --git a/lib/ts/bwf_std_format.h b/lib/ts/bwf_std_format.h index 9ea50a5..fdc998f 100644 --- a/lib/ts/bwf_std_format.h +++ b/lib/ts/bwf_std_format.h @@ -34,3 +34,17 @@ bwformat(ts::BufferWriter &w, ts::BWFSpec const &spec, std::atomic<T> const &v) return ts::bwformat(w, spec, v.load()); } } // end namespace std + +namespace ts +{ +namespace bwf +{ + struct Errno { + int _e; + explicit Errno(int e) : _e(e) {} + }; +} // namespace bwf + +BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, bwf::Errno const &e); + +} // namespace ts diff --git a/lib/ts/unit-tests/test_BufferWriterFormat.cc b/lib/ts/unit-tests/test_BufferWriterFormat.cc index 14986f8..f1f5f3a 100644 --- a/lib/ts/unit-tests/test_BufferWriterFormat.cc +++ b/lib/ts/unit-tests/test_BufferWriterFormat.cc @@ -481,6 +481,16 @@ TEST_CASE("BWFormat floating", "[bwprint][bwformat]") bw.reduce(0); } +TEST_CASE("bwstring std formats", "[libts][bwprint]") +{ + ts::LocalBufferWriter<120> w; + + w.print("{}", ts::bwf::Errno(13)); + REQUIRE(w.view() == "EACCES: Permission denied [13]"sv); + w.reset().print("{}", ts::bwf::Errno(134)); + REQUIRE(w.view().substr(0, 22) == "Unknown: Unknown error"sv); +} + // Normally there's no point in running the performance tests, but it's worth keeping the code // for when additional testing needs to be done. #if 0