aboutsummaryrefslogtreecommitdiff
path: root/include/cru/common/format.hpp
blob: ecc4b30bf00b772df8c496dfb30233b61510498d (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
#pragma once
#include "pre_config.hpp"

#include <string>
#include <string_view>

namespace cru::util {
namespace details {
template <typename T>
struct TypeTag {};

constexpr std::wstring_view PlaceHolder(TypeTag<std::wstring>) {
  return std::wstring_view(L"{}");
}

constexpr std::string_view PlaceHolder(TypeTag<std::string>) {
  return std::string_view("{}");
}

template <typename TString>
void FormatInternal(TString& string) {
  const auto find_result = string.find(PlaceHolder(TypeTag<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(TypeTag<TString>{}));
  if (find_result == TString::npos)
    throw std::invalid_argument("There is less placeholders than args.");

  string.replace(find_result, 2, FormatToString(arg, TypeTag<TString>{}));
  FormatInternal<TString>(string, args...);
}
}  // namespace details

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

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

#define CRU_FORMAT_NUMBER(type)                                        \
  inline std::string FormatToString(const type number,                 \
                                    details::TypeTag<std::string>) {   \
    return std::to_string(number);                                     \
  }                                                                    \
  inline std::wstring FormatToString(const type number,                \
                                     details::TypeTag<std::wstring>) { \
    return std::to_wstring(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 std::wstring_view FormatToString(const std::wstring& string,
                                        details::TypeTag<std::wstring>) {
  return string;
}

inline std::string_view FormatToString(const std::string& string,
                                       details::TypeTag<std::string>) {
  return string;
}

inline std::wstring_view FormatToString(const std::wstring_view& string,
                                        details::TypeTag<std::wstring>) {
  return string;
}

inline std::string_view FormatToString(const std::string_view& string,
                                       details::TypeTag<std::string>) {
  return string;
}

inline std::wstring_view FormatToString(const wchar_t* string,
                                        details::TypeTag<std::wstring>) {
  return std::wstring_view(string);
}

inline std::string_view FormatToString(const char* string,
                                       details::TypeTag<std::string>) {
  return std::string_view(string);
}
}  // namespace cru::util