aboutsummaryrefslogtreecommitdiff
path: root/src/format.hpp
blob: 3f6253ffceb81f7a90b7fac021be5e432e3aa1f7 (plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#pragma once

#include "base.hpp"

namespace cru
{
    namespace details
    {
        constexpr StringView PlaceHolder(type_tag<String>)
        {
            return StringView(L"{}");
        }

        constexpr MultiByteStringView PlaceHolder(type_tag<MultiByteString>)
        {
            return MultiByteStringView("{}");
        }

        template<typename TString>
        void FormatInternal(TString& string)
        {
            const auto find_result = string.find(PlaceHolder(type_tag<TString>{}));
            if (find_result != TString::npos)
                throw std::invalid_argument("There is more placeholders than args.");
        }

        template<typename TString, typename T, typename... TRest>
        void FormatInternal(TString& string, const T& arg, const TRest&... args)
        {
            const auto find_result = string.find(PlaceHolder(type_tag<TString>{}));
            if (find_result == TString::npos)
                throw std::invalid_argument("There is less placeholders than args.");

            string.replace(find_result, 2, FormatToString(arg, type_tag<TString>{}));
            FormatInternal<TString>(string, args...);
        }
    }

    template<typename... T>
    String Format(const StringView& format, const T&... args)
    {
        String result(format);
        details::FormatInternal<String>(result, args...);
        return result;
    }

    template<typename... T>
    MultiByteString Format(const MultiByteStringView& format, const T&... args)
    {
        MultiByteString result(format);
        details::FormatInternal<MultiByteString>(result, args...);
        return result;
    }

#define CRU_FORMAT_NUMBER(type) \
    inline String FormatToString(const type number, type_tag<String>) \
    { \
        return std::to_wstring(number); \
    } \
    inline MultiByteString FormatToString(const type number, type_tag<MultiByteString>) \
    { \
        return std::to_string(number); \
    }

    CRU_FORMAT_NUMBER(int)
    CRU_FORMAT_NUMBER(short)
    CRU_FORMAT_NUMBER(long)
    CRU_FORMAT_NUMBER(long long)
    CRU_FORMAT_NUMBER(unsigned int)
    CRU_FORMAT_NUMBER(unsigned short)
    CRU_FORMAT_NUMBER(unsigned long)
    CRU_FORMAT_NUMBER(unsigned long long)
    CRU_FORMAT_NUMBER(float)
    CRU_FORMAT_NUMBER(double)

#undef CRU_FORMAT_NUMBER

    inline StringView FormatToString(const String& string, type_tag<String>)
    {
        return string;
    }

    inline MultiByteString FormatToString(const MultiByteString& string, type_tag<MultiByteString>)
    {
        return string;
    }

    inline StringView FormatToString(const StringView& string, type_tag<String>)
    {
        return string;
    }

    inline MultiByteStringView FormatToString(const MultiByteStringView& string, type_tag<MultiByteString>)
    {
        return string;
    }

    inline StringView FormatToString(const wchar_t* string, type_tag<String>)
    {
        return StringView(string);
    }

    inline MultiByteStringView FormatToString(const char* string, type_tag<MultiByteString>)
    {
        return MultiByteString(string);
    }
}