libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

format_string.hpp (1936B)


      1 #ifndef TEST_SUPPORT_FORMAT_STRING_HPP
      2 #define TEST_SUPPORT_FORMAT_STRING_HPP
      3 
      4 #include <cstdio>
      5 #include <string>
      6 #include <memory>
      7 #include <array>
      8 #include <cstdarg>
      9 
     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-emptivly make a copy
     13   struct GuardVAList {
     14     va_list& xtarget;
     15     bool active;
     16     GuardVAList(va_list& val) : xtarget(val), active(true) {}
     17 
     18     void clear() {
     19       if (active)
     20         va_end(xtarget);
     21       active = false;
     22     }
     23     ~GuardVAList() {
     24       if (active)
     25         va_end(xtarget);
     26     }
     27   };
     28   va_list args;
     29   va_start(args, msg);
     30   GuardVAList args_guard(args);
     31 
     32   va_list args_cp;
     33   va_copy(args_cp, args);
     34   GuardVAList args_copy_guard(args_cp);
     35 
     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);
     39 
     40   args_copy_guard.clear();
     41 
     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());
     47 
     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());
     54 }
     55 
     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;
     61 }
     62 
     63 } // namespace format_string_detail
     64 
     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))...);
     69 }
     70 
     71 #endif // TEST_SUPPORT_FORMAT_STRING_HPP