[flang][runtime] Make defined formatted I/O process format elementally (#74150)
[llvm-project.git] / libcxx / test / support / format_string.h
blob230f2e475d59962a2ab2a7a0d13cd9cd5846ae4f
1 #ifndef TEST_SUPPORT_FORMAT_STRING_H
2 #define TEST_SUPPORT_FORMAT_STRING_H
4 #include <cstdio>
5 #include <string>
6 #include <memory>
7 #include <array>
8 #include <cstdarg>
10 namespace format_string_detail {
11 inline std::string format_string_imp(const char* msg, ...) {
12 // we might need a second shot at this, so pre-emptively make a copy
13 struct GuardVAList {
14 va_list& xtarget;
15 bool active;
16 GuardVAList(va_list& val) : xtarget(val), active(true) {}
18 void clear() {
19 if (active)
20 va_end(xtarget);
21 active = false;
23 ~GuardVAList() {
24 if (active)
25 va_end(xtarget);
28 va_list args;
29 va_start(args, msg);
30 GuardVAList args_guard(args);
32 va_list args_cp;
33 va_copy(args_cp, args);
34 GuardVAList args_copy_guard(args_cp);
36 std::array<char, 256> local_buff;
37 std::size_t size = local_buff.size();
38 auto ret = ::vsnprintf(local_buff.data(), size, msg, args_cp);
40 args_copy_guard.clear();
42 // handle empty expansion
43 if (ret == 0)
44 return std::string{};
45 if (static_cast<std::size_t>(ret) < size)
46 return std::string(local_buff.data());
48 // we did not provide a long enough buffer on our first attempt.
49 // add 1 to size to account for null-byte in size cast to prevent overflow
50 size = static_cast<std::size_t>(ret) + 1;
51 auto buff_ptr = std::unique_ptr<char[]>(new char[size]);
52 ret = ::vsnprintf(buff_ptr.get(), size, msg, args);
53 return std::string(buff_ptr.get());
56 const char* unwrap(std::string& s) { return s.c_str(); }
57 template <class Arg>
58 Arg const& unwrap(Arg& a) {
59 static_assert(!std::is_class<Arg>::value, "cannot pass class here");
60 return a;
63 } // namespace format_string_detail
65 template <class... Args>
66 std::string format_string(const char* fmt, Args const&... args) {
67 return format_string_detail::format_string_imp(
68 fmt, format_string_detail::unwrap(const_cast<Args&>(args))...);
71 #endif // TEST_SUPPORT_FORMAT_STRING_HPP