From 9f7dffb109a936981ca679accedbf61ccf785379 Mon Sep 17 00:00:00 2001 From: Scott McKay Date: Sat, 20 Feb 2021 20:41:19 +1000 Subject: [PATCH] Make it easier to fold MakeString usages to reduce binary size. (#6754) * Decay char[n] to char* so that we get better re-use of MakeString invocations. --- include/onnxruntime/core/common/make_string.h | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/include/onnxruntime/core/common/make_string.h b/include/onnxruntime/core/common/make_string.h index a6e421a61e..826898de85 100644 --- a/include/onnxruntime/core/common/make_string.h +++ b/include/onnxruntime/core/common/make_string.h @@ -19,10 +19,12 @@ #include #include +#include namespace onnxruntime { namespace detail { + inline void MakeStringImpl(std::ostringstream& /*ss*/) noexcept { } @@ -36,6 +38,39 @@ inline void MakeStringImpl(std::ostringstream& ss, const T& t, const Args&... ar MakeStringImpl(ss, t); MakeStringImpl(ss, args...); } + +// see MakeString comments for explanation of why this is necessary +template +inline std::string MakeStringImpl(const Args&... args) noexcept { + std::ostringstream ss; + MakeStringImpl(ss, args...); + return ss.str(); +} + +// +// Infrastructure to convert char[n] to char* to reduce binary size +// + +// default is to leave the type as is +template +struct if_char_array_make_ptr { + using type = T; +}; + +// specialization that matches an array reference, which is what the char array from a string literal +// used in a call to MakeString will be. +// if the type is a char[n] array we 'decay' it to a char* so that the usages can be folded. +template +struct if_char_array_make_ptr { + // remove a single extent (T[x] -> T, but T[x][y] -> T[y]) so we only match char[x], + // and get the type name without the 'const' so both 'const char (&)[n]' and 'char (&)[n]' are matched. + using element_type = typename std::remove_const::type>::type; + using type = typename std::conditional::value, T*, T (&)[N]>::type; +}; + +// helper to make usage simpler in MakeString +template +using if_char_array_make_ptr_t = typename if_char_array_make_ptr::type; } // namespace detail /** @@ -44,9 +79,18 @@ inline void MakeStringImpl(std::ostringstream& ss, const T& t, const Args&... ar */ template std::string MakeString(const Args&... args) { - std::ostringstream ss; - detail::MakeStringImpl(ss, args...); - return ss.str(); + // We need to update the types from the MakeString template instantiation to decay any char[n] to char*. + // e.g. MakeString("in", "out") goes from MakeString to MakeStringImpl + // so that MakeString("out", "in") will also match MakeStringImpl instead of requiring + // MakeStringImpl. + // + // We have to do the type processing before any actual work, so this function purely implements the type processing. + // If we do not do it this way we do not get the full binary size reduction. + // + // See https://stackoverflow.com/a/29418212/684911 for overall details of the approach, but note it does not cover + // the need to do the type processing as a separate step. + + return detail::MakeStringImpl(detail::if_char_array_make_ptr_t(args)...); } /**