From 6dafc45b8bd22cbc1f53a659ac56caa83256ecec Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 7 May 2021 11:44:02 +0100 Subject: [PATCH] Allow custom string argument formatting without va_list --- renderdoc/common/formatting.h | 13 +++++ renderdoc/os/os_specific.cpp | 15 ++++++ renderdoc/strings/utf8printf.cpp | 85 ++++++++++++++++++++++++++++---- 3 files changed, 104 insertions(+), 9 deletions(-) diff --git a/renderdoc/common/formatting.h b/renderdoc/common/formatting.h index e83a9cc24..c1d738d54 100644 --- a/renderdoc/common/formatting.h +++ b/renderdoc/common/formatting.h @@ -28,5 +28,18 @@ namespace StringFormat { +struct Args +{ + virtual void reset() = 0; + + virtual int get_int() = 0; + virtual unsigned int get_uint() = 0; + virtual double get_double() = 0; + virtual void *get_ptr() = 0; + virtual uint64_t get_uint64() = 0; + virtual size_t get_size() = 0; +}; + rdcstr Fmt(const char *format, ...); +rdcstr FmtArgs(const char *format, Args &args); }; diff --git a/renderdoc/os/os_specific.cpp b/renderdoc/os/os_specific.cpp index fe92b4941..3669987d5 100644 --- a/renderdoc/os/os_specific.cpp +++ b/renderdoc/os/os_specific.cpp @@ -25,9 +25,11 @@ #include "os/os_specific.h" #include "api/replay/control_types.h" +#include "common/formatting.h" #include "strings/string_utils.h" int utf8printv(char *buf, size_t bufsize, const char *fmt, va_list args); +int utf8printf_custom(char *buf, size_t bufSize, const char *fmt, StringFormat::Args &args); bool Network::ParseIPRangeCIDR(const rdcstr &str, uint32_t &ip, uint32_t &mask) { @@ -83,6 +85,19 @@ rdcstr Fmt(const char *format, ...) return ret; } +rdcstr FmtArgs(const char *format, Args &args) +{ + int size = ::utf8printf_custom(NULL, 0, format, args); + + args.reset(); + + rdcstr ret; + ret.resize(size); + ::utf8printf_custom(ret.data(), size + 1, format, args); + + return ret; +} + }; // namespace StringFormat rdcstr Callstack::AddressDetails::formattedString(const rdcstr &commonPath) diff --git a/renderdoc/strings/utf8printf.cpp b/renderdoc/strings/utf8printf.cpp index b14d7875c..a5a896d91 100644 --- a/renderdoc/strings/utf8printf.cpp +++ b/renderdoc/strings/utf8printf.cpp @@ -24,6 +24,7 @@ #include #include "common/common.h" +#include "common/formatting.h" #include "os/os_specific.h" // grisu2 double-to-string function, returns number of digits written to digits array @@ -1407,7 +1408,60 @@ void formatargument(char type, void *rawarg, FormatterParams formatter, char *&o } } -int utf8printv(char *buf, size_t bufsize, const char *fmt, va_list args) +struct va_arg_getter +{ + va_list list; + va_arg_getter(va_list l) { va_copy(list, l); } + template + inline T get_next() + { + return va_arg(list, T); + } +}; + +struct custom_arg_getter +{ + StringFormat::Args &formatter; + custom_arg_getter(StringFormat::Args &f) : formatter(f) {} + template + inline T get_next(); +}; + +template <> +inline int custom_arg_getter::get_next() +{ + return formatter.get_int(); +} +template <> +inline unsigned int custom_arg_getter::get_next() +{ + return formatter.get_uint(); +} +template <> +inline double custom_arg_getter::get_next() +{ + return formatter.get_double(); +} +template <> +inline void *custom_arg_getter::get_next() +{ + return formatter.get_ptr(); +} +template <> +inline uint64_t custom_arg_getter::get_next() +{ + return formatter.get_uint64(); +} +#if ENABLED(RDOC_SIZET_SEP_TYPE) +template <> +inline size_t custom_arg_getter::get_next() +{ + return formatter.get_size(); +} +#endif + +template +int utf8print_template(char *buf, size_t bufsize, const char *fmt, arg_getter args) { // format, buffer and string arguments are assumed to be UTF-8 (except wide strings). // note that since the format specifiers are entirely ascii, we can byte-copy safely and handle @@ -1600,18 +1654,18 @@ int utf8printv(char *buf, size_t bufsize, const char *fmt, va_list args) if(type == 'c') { int *i = (int *)arg; - *i = va_arg(args, int); + *i = args.template get_next(); } else if(type == 's' || type == 'p') { void **p = (void **)arg; - *p = va_arg(args, void *); + *p = args.template get_next(); } else if(type == 'e' || type == 'E' || type == 'f' || type == 'F' || type == 'g' || type == 'G' || type == 'a' || type == 'A') { double *i = (double *)arg; - *i = va_arg(args, double); + *i = args.template get_next(); } else if(type == 'b' || type == 'B' || type == 'o' || type == 'x' || type == 'X' || type == 'd' || type == 'i' || type == 'u') @@ -1619,17 +1673,17 @@ int utf8printv(char *buf, size_t bufsize, const char *fmt, va_list args) if(formatter.Length == LongLong) { uint64_t *ull = (uint64_t *)arg; - *ull = va_arg(args, uint64_t); + *ull = args.template get_next(); } else if(formatter.Length == SizeT) { size_t *s = (size_t *)arg; - *s = va_arg(args, size_t); + *s = args.template get_next(); } else { unsigned int *u = (unsigned int *)arg; - *u = va_arg(args, unsigned int); + *u = args.template get_next(); } } else @@ -1688,18 +1742,31 @@ int utf8printv(char *buf, size_t bufsize, const char *fmt, va_list args) return int(actualsize); } -int utf8printf(char *str, size_t bufSize, const char *fmt, ...) +int utf8printv(char *buf, size_t bufSize, const char *fmt, va_list args) +{ + va_arg_getter getter(args); + return utf8print_template(buf, bufSize, fmt, getter); +} + +int utf8printf(char *buf, size_t bufSize, const char *fmt, ...) { va_list args; va_start(args, fmt); - int ret = utf8printv(str, bufSize, fmt, args); + va_arg_getter getter(args); + int ret = utf8print_template(buf, bufSize, fmt, getter); va_end(args); return ret; } +int utf8printf_custom(char *buf, size_t bufSize, const char *fmt, StringFormat::Args &args) +{ + custom_arg_getter getter(args); + return utf8print_template(buf, bufSize, fmt, getter); +} + #if ENABLED(ENABLE_UNIT_TESTS) #include "catch/catch.hpp"