string: add sprintf and appendf

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2023-07-17 14:56:29 +02:00
parent 863d37546e
commit f55d5636aa

View File

@ -804,4 +804,97 @@ namespace stdex
return (size_t)strtou32(str, count, end, radix); return (size_t)strtou32(str, count, end, radix);
#endif #endif
} }
/// \cond internal
inline int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg)
{
#if _MSC_VER <= 1600
#pragma warning(suppress: 4996)
return _vsnprintf(str, capacity, format, arg);
#else
#pragma warning(suppress: 4996)
return ::vsnprintf(str, capacity, format, arg);
#endif
}
inline int vsnprintf(_Out_z_cap_(capacity) wchar_t *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const wchar_t *format, _In_ va_list arg) noexcept
{
#pragma warning(suppress: 4996)
return _vsnwprintf(str, capacity, format, arg);
}
/// \endcond
///
/// Formats string using `printf()`.
///
/// \param[out] str String to append formatted text
/// \param[in ] format String template using `printf()` style
/// \param[in ] arg Arguments to `format`
///
template<class _Elem, class _Traits, class _Ax>
inline void vappendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg)
{
_Elem buf[1024/sizeof(_Elem)];
// Try with stack buffer first.
int count = vsnprintf(buf, _countof(buf) - 1, format, arg);
if (count >= 0) {
// Copy from stack.
str.append(buf, count);
} else {
for (size_t capacity = 2*1024/sizeof(_Elem);; capacity *= 2) {
// Allocate on heap and retry.
auto buf_dyn = std::make_unique<_Elem[]>(capacity);
count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg);
if (count >= 0) {
str.append(buf_dyn.get(), count);
break;
}
}
}
}
///
/// Formats string using `printf()`.
///
/// \param[out] str String to append formatted text
/// \param[in ] format String template using `printf()` style
///
template<class _Elem, class _Traits, class _Ax>
inline void appendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...)
{
va_list arg;
va_start(arg, format);
vappendf(str, format, arg);
va_end(arg);
}
///
/// Formats string using `printf()`.
///
/// \param[out] str Formatted string
/// \param[in ] format String template using `printf()` style
/// \param[in ] arg Arguments to `format`
///
template<class _Elem, class _Traits, class _Ax>
inline void vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg)
{
str.clear();
appendf(str, format, arg);
}
///
/// Formats string using `printf()`.
///
/// \param[out] str Formatted string
/// \param[in ] format String template using `printf()` style
///
template<class _Elem, class _Traits, class _Ax>
inline void sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...)
{
va_list arg;
va_start(arg, format);
vsprintf(str, format, arg);
va_end(arg);
}
} }