File: format.hpp

package info (click to toggle)
openmw 0.50.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 37,076 kB
  • sloc: cpp: 380,958; xml: 2,192; sh: 1,449; python: 911; makefile: 26; javascript: 5
file content (79 lines) | stat: -rw-r--r-- 2,707 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#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