xtd 0.2.0
__formatter.hpp
Go to the documentation of this file.
1
3#pragma once
4#include <bitset>
5#include <cmath>
6#include <cstdarg>
7#include <iomanip>
8#include <locale>
9#include <sstream>
10#include <string>
11#include <type_traits>
12#include <vector>
13#include "../helpers/throw_helper.hpp"
14#include "../iformatable.hpp"
15#include "../int32.hpp"
16#include "../int64.hpp"
17#include "../istringable.hpp"
18#include "../object.hpp"
19
21// defined in enum_object.hpp
22// {
23template<class enum_t>
24std::string __enum_to_string__(enum_t value) noexcept;
25// }
26
27// defined in object.cpp
28// {
29std::string __object_to_string__(const xtd::object& obj) noexcept;
30std::string __istringable_to_string__(const xtd::istringable& stringable) noexcept;
31// }
32
33inline const char* __sprintf__(const char* fmt, ...) noexcept {
34 std::va_list args;
35 va_start(args, fmt);
36 thread_local auto result = std::string(vsnprintf(nullptr, 0, fmt, args), 0);
37 va_end(args);
38 va_start(args, fmt);
39 vsnprintf(&result[0], result.size() + 1, fmt, args);
40 va_end(args);
41 if (result == "INF") result = "inf";
42 if (result == "-INF") result = "-inf";
43 if (result == "NAN") result = "nan";
44 return result.c_str();
45}
46
47template<class value_t>
48inline std::string __binary_formatter__(value_t value, xtd::int32 precision) {
49 auto result = std::bitset<sizeof(value) * 8>(value).to_string('0', '1');
50 while (result[0] != 0 && result[0] == '0')
51 result.erase(0, 1);
52 if (precision < 0 && result.size() > size_t(std::abs(precision)))
53 result.append(result.size() - std::abs(precision), ' ');
54 else {
55 if (precision == 0) precision = 1;
56 if (size_t(precision) > result.size())
57 result.insert(0, size_t(precision) - result.size(), '0');
58 }
59 return result;
60}
61
62inline std::string __currency_formatter__(long double value, const std::locale& locale) {
63 auto ss = std::stringstream {};
64 ss.imbue(locale);
65 ss << std::showbase << std::fixed << std::put_money(value * std::pow(10, std::use_facet<std::moneypunct<char>>(locale).frac_digits()));
66 return ss.str();
67}
68
69inline std::string __hexfloat_formatter__(long double value, xtd::int32 precision, const std::locale& loc) {
70 auto ss = std::stringstream {};
71 ss.imbue(loc);
72 ss << std::hexfloat << std::setprecision(precision) << value;
73 return ss.str();
74}
75
76template<class floating_point_t>
77inline std::string __floating_point_to_binary__(floating_point_t value, xtd::int32 precision) {
78 union {
79 double input;
80 int64_t output;
81 } data;
82 data.input = value;
83 return __binary_formatter__(data.output, precision);
84}
85
86inline std::string __natural_formatter__(long double value, xtd::int32 precision, const std::locale& locale) {
87 auto ss = std::stringstream {};
88 ss.imbue(locale);
89 ss << std::fixed << std::setprecision(precision) << value;
90 return ss.str();
91}
92
93template <>
94inline std::string __floating_point_to_binary__<long double>(long double value, xtd::int32 precision) {
95 union {
96 long double input;
97 int64_t output;
98 } data;
99 data.input = value;
100 return __binary_formatter__(data.output, precision);
101}
102
103template <>
104inline std::string __floating_point_to_binary__<double>(double value, xtd::int32 precision) {
105 union {
106 double input;
107 int64_t output;
108 } data;
109 data.input = value;
110 return __binary_formatter__(data.output, precision);
111}
112
113template <>
114inline std::string __floating_point_to_binary__<float>(float value, xtd::int32 precision) {
115 union {
116 float input;
117 int32_t output;
118 } data;
119 data.input = value;
120 return __binary_formatter__(data.output, precision);
121}
122
123template<class type_t>
124inline std::string __floating_point_formatter__(type_t value, const std::string& format, const std::locale& locale) {
125 auto fmt = !format.empty() ? format : "G";
126 auto possible_formats = {'b', 'B', 'c', 'C', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'N', 'p', 'P', 'x', 'X'};
127 if (fmt.size() > 3 || std::find(possible_formats.begin(), possible_formats.end(), fmt[0]) == possible_formats.end() || (fmt.size() >= 2 && !std::isdigit(fmt[1])) || (fmt.size() == 3 && !std::isdigit(fmt[2])))
129
130 auto precision = 0;
131 try {
132 if (fmt.size() > 1) precision = std::stoi(fmt.substr(1));
133 } catch (...) {
135 }
136 if ((fmt[0] == 'f' || fmt[0] == 'F' || fmt[0] == 'n' || fmt[0] == 'N' || fmt[0] == 'p' || fmt[0] == 'P' || fmt[0] == 'r' || fmt[0] == 'R') && fmt.size() == 1) precision = 2;
137 if ((fmt[0] == 'e' || fmt[0] == 'E') && fmt.size() == 1) precision = 6;
138 if ((fmt[0] == 'g' || fmt[0] == 'G') && fmt.size() == 1) precision = sizeof(value) <= 4 ? 7 : 15;
139
140 auto fmt_str = std::string {"%.*L"};
141 switch (fmt[0]) {
142 case 'b':
143 case 'B': return __floating_point_to_binary__<char>(value, precision);
144 case 'c':
145 case 'C': return __currency_formatter__(static_cast<long double>(value), locale);
146 case 'e':
147 case 'E':
148 case 'f':
149 case 'F':
150 case 'g':
151 case 'G': return __sprintf__((fmt_str + fmt[0]).c_str(), precision, static_cast<long double>(value));
152 case 'n':
153 case 'N': return __natural_formatter__(static_cast<long double>(value), precision, locale);
154 case 'p': return std::string {__sprintf__((fmt_str + 'f').c_str(), precision, static_cast<long double>(value * 100))} + std::string {" %"};
155 case 'P': return std::string {__sprintf__((fmt_str + 'F').c_str(), precision, static_cast<long double>(value * 100))} + std::string {" %"};
156 case 'x':
157 case 'X': return __hexfloat_formatter__(static_cast<long double>(value), precision, locale);
159 }
160}
161
162template<class type_t>
163inline std::string __numeric_formatter__(type_t value, const std::string& format, const std::locale& locale) {
164 auto fmt = !format.empty() ? format : "G";
165 auto possible_formats = {'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'N', 'o', 'O', 'p', 'P', 'x', 'X'};
166 if (fmt.size() > 3 || std::find(possible_formats.begin(), possible_formats.end(), fmt[0]) == possible_formats.end() || (fmt.size() >= 2 && !std::isdigit(fmt[1])) || (fmt.size() == 3 && !std::isdigit(fmt[2])))
168
169 auto precision = 0;
170 if (fmt[0] == 'b' || fmt[0] == 'B' || fmt[0] == 'd' || fmt[0] == 'D' || fmt[0] == 'o' || fmt[0] == 'O' || fmt[0] == 'x' || fmt[0] == 'X') {
171 try {
172 for (auto c : fmt.substr(1))
173 if (!std::isdigit(c) && c != ' ' && c != '+' && c != '-') xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "Invalid fmt expression");
174 if (fmt.size() > 1) precision = std::stoi(fmt.substr(1));
175 } catch (...) {
177 }
178 if ((fmt[0] == 'd' || fmt[0] == 'D') && precision > 0 && value < 0) precision += 1;
179 if ((fmt[0] == 'd' || fmt[0] == 'D') && precision < 0 && value < 0) precision -= 1;
180 }
181
182 switch (fmt[0]) {
183 case 'b':
184 case 'B': return __binary_formatter__(value, precision);
185 case 'd':
186 case 'D':
187 case 'G': return __sprintf__((std::string {"%0*ll"} + (std::is_unsigned<type_t>::value ? 'u' : 'd')).c_str(), precision, static_cast<long long>(value));
188 case 'o':
189 case 'O': return __sprintf__((std::string {"%0*ll"} + 'o').c_str(), precision, static_cast<long long>(value));
190 case 'x':
191 case 'X': return __sprintf__((std::string {"%0*ll"} + fmt[0]).c_str(), precision, static_cast<long long>(value));
192 default: return __floating_point_formatter__(static_cast<long double>(value), fmt, locale);
193 }
194}
195
196template<class type_t>
197inline std::string __enum_formatter__(type_t value, const std::string& format, const std::locale& locale, std::true_type) {
198 auto fmt = !format.empty() ? format : "G";
199 switch (fmt[0]) {
200 case 'b':
201 case 'B':
202 case 'd':
203 case 'D':
204 case 'o':
205 case 'O':
206 case 'x':
207 case 'X': return {}; __numeric_formatter__(static_cast<xtd::int64>(value), format, locale);
208 case 'g':
209 case 'G': return {}; __enum_to_string__(value);
211 }
212}
213
214template<class type_t>
215inline std::string __enum_formatter__(const type_t& value, const std::string& format, const std::locale& locale, std::false_type) {
217}
218
219template<class type_t>
220inline std::string __polymorphic_formatter__(const type_t& value, const std::string& format, const std::locale& locale, std::true_type) {
221 if (dynamic_cast<const xtd::iformatable*>(&value)) return dynamic_cast<const xtd::iformatable&>(value).__opague_internal_formatable__(reinterpret_cast<intptr_t>(&format), reinterpret_cast<intptr_t>(&locale), 0, INTPTR_MAX);
222 if (dynamic_cast<const xtd::istringable*>(&value)) return __istringable_to_string__(dynamic_cast<const xtd::istringable&>(value));
223 if (dynamic_cast<const xtd::object*>(&value)) return __object_to_string__(dynamic_cast<const xtd::object&>(value));
224 if (dynamic_cast<const std::exception*>(&value)) return std::string {"exception: "} + dynamic_cast<const std::exception&>(value).what();
226}
227
228template <class type_t>
229inline std::string __workaround_char8_t_enum_formatter__(const type_t& value, const std::string& format, const std::locale& locale) {
230 return __enum_formatter__(value, format, locale, std::is_enum<type_t>());
231}
232
233inline std::string __workaround_char8_t_enum_formatter__(const char8_t& value, const std::string& format, const std::locale& locale) {
234 xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format_not_iformatable, "The `char8_t` type does not inherit from `xtd::iformat` or the specialisation for the `{char8_t}` type in the `xtd::to_string` specialisation method does not exist.");
235}
236
237inline std::string __workaround_char8_t_enum_formatter__(const char8_t* value, const std::string& format, const std::locale& locale) {
238 xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format_not_iformatable, "The `char8_t` type does not inherit from `xtd::iformat` or the specialisation for the `{char8_t}` type in the `xtd::to_string` specialisation method does not exist.");
239}
240
241template<class type_t>
242inline std::string __polymorphic_formatter__(const type_t& value, const std::string& format, const std::locale& locale, std::false_type) {
243 return __workaround_char8_t_enum_formatter__(value, format, locale);
244}
bool empty() const noexcept
Checks if the string has no characters, i.e. whether begin() == end().
Definition basic_string.hpp:896
static void throws(xtd::helpers::exception_case exception_case, const source_location &location=source_location::current())
Throws an exption with specified exception case.
Provides functionality to format the value of an object into a string representation.
Definition iformatable.hpp:35
Provides a way to represent the current object as a string.
Definition istringable.hpp:23
Supports all classes in the xtd class hierarchy and provides low-level services to derived classes....
Definition object.hpp:44
xtd::string format(const xtd::string &fmt, args_t &&... args)
Writes the text representation of the specified arguments list, to string using the specified format ...
Definition format.hpp:20
exception_case
Represents the exception case used by the xtd::helpers::exception helper class.
Definition exception_case.hpp:25
@ format_not_iformatable
The object is not iformatable.
@ format
The format is not valid.
int32_t int32
Represents a 32-bit signed integer.
Definition int32.hpp:23
int64_t int64
Represents a 64-bit signed integer.
Definition int64.hpp:23
@ c
The C key.
The xtd namespace contains all fundamental classes to access Hardware, Os, System,...
Definition xtd_about_box.hpp:10