mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 01:56:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			79 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			79 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef COMPONENTS_MISC_STRINGS_FORMAT_H
 | |
| #define COMPONENTS_MISC_STRINGS_FORMAT_H
 | |
| 
 | |
| #include <MyGUI_UString.h>
 | |
| #include <cerrno>
 | |
| #include <cstdio>
 | |
| #include <cstring>
 | |
| #include <stdexcept>
 | |
| #include <string>
 | |
| #include <string_view>
 | |
| #include <system_error>
 | |
| #include <vector>
 | |
| 
 | |
| namespace Misc::StringUtils
 | |
| {
 | |
|     namespace Details
 | |
|     {
 | |
|         // Allow to convert complex arguments to C-style strings for format() function
 | |
|         template <typename T>
 | |
|         T argument(T value) noexcept
 | |
|         {
 | |
|             static_assert(!std::is_same_v<T, std::string_view>, "std::string_view is not supported");
 | |
|             static_assert(!std::is_same_v<T, MyGUI::UString>, "MyGUI::UString is not supported");
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         template <typename T>
 | |
|         T const* argument(std::basic_string<T> const& value) noexcept
 | |
|         {
 | |
|             return value.c_str();
 | |
|         }
 | |
| 
 | |
|         template <class T>
 | |
|         T nullTerminated(T value) noexcept
 | |
|         {
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         template <class T>
 | |
|         std::basic_string<T> nullTerminated(const std::basic_string_view<T>& value) noexcept
 | |
|         {
 | |
|             // Ensure string_view arguments are null-terminated by creating a string
 | |
|             // TODO: Use a format function that doesn't require this workaround
 | |
|             return std::string{ value };
 | |
|         }
 | |
| 
 | |
|         // Requires some C++11 features:
 | |
|         // 1. std::string needs to be contiguous
 | |
|         // 2. std::snprintf with zero size (second argument) returns an output string size
 | |
|         // 3. variadic templates support
 | |
|         template <typename... Args>
 | |
|         std::string format(const char* fmt, Args const&... args)
 | |
|         {
 | |
|             const int size = std::snprintf(nullptr, 0, fmt, argument(args)...);
 | |
|             if (size < 0)
 | |
|                 throw std::system_error(errno, std::generic_category(), "Failed to compute resulting string size");
 | |
|             // Note: sprintf also writes a trailing null character. We should remove it.
 | |
|             std::string ret(static_cast<std::size_t>(size) + 1, '\0');
 | |
|             if (std::sprintf(ret.data(), fmt, argument(args)...) < 0)
 | |
|                 throw std::system_error(errno, std::generic_category(), "Failed to format string");
 | |
|             ret.erase(static_cast<std::size_t>(size));
 | |
|             return ret;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <typename... Args>
 | |
|     std::string format(const char* fmt, Args const&... args)
 | |
|     {
 | |
|         return Details::format(fmt, Details::nullTerminated(args)...);
 | |
|     }
 | |
| 
 | |
|     template <typename... Args>
 | |
|     std::string format(const std::string& fmt, Args const&... args)
 | |
|     {
 | |
|         return Details::format(fmt.c_str(), Details::nullTerminated(args)...);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif
 |