Skip to content

Commit dffa335

Browse files
committed
Add locale support to <format> support
1 parent 642867b commit dffa335

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

include/boost/decimal/format.hpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ constexpr auto parse_impl(ParseContext &ctx)
4747
boost::decimal::chars_format fmt = boost::decimal::chars_format::general;
4848
bool is_upper = false;
4949
int padding_digits = 0;
50+
bool use_locale = false;
51+
52+
// Check for the locale character
53+
if (*it == 'L')
54+
{
55+
use_locale = true;
56+
++it;
57+
}
5058

5159
// Check for a sign character
5260
if (it != ctx.end())
@@ -148,7 +156,7 @@ constexpr auto parse_impl(ParseContext &ctx)
148156
BOOST_DECIMAL_THROW_EXCEPTION(std::format_error("Expected '}' in format string")); // LCOV_EXCL_LINE
149157
}
150158

151-
return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, sign_character, it);
159+
return std::make_tuple(ctx_precision, fmt, is_upper, padding_digits, sign_character, use_locale, it);
152160
}
153161

154162
} // Namespace boost::decimal::detail
@@ -163,12 +171,14 @@ struct formatter<T>
163171
int ctx_precision;
164172
int padding_digits;
165173
bool is_upper;
174+
bool use_locale;
166175

167176
constexpr formatter() : fmt(boost::decimal::chars_format::general),
168177
sign(boost::decimal::detail::format_sign_option::minus),
169178
ctx_precision(6),
170179
padding_digits(0),
171-
is_upper(false)
180+
is_upper(false),
181+
use_locale(false)
172182
{}
173183

174184
constexpr auto parse(format_parse_context &ctx)
@@ -180,8 +190,9 @@ struct formatter<T>
180190
is_upper = std::get<2>(res);
181191
padding_digits = std::get<3>(res);
182192
sign = std::get<4>(res);
193+
use_locale = std::get<5>(res);
183194

184-
return std::get<5>(res);
195+
return std::get<6>(res);
185196
}
186197

187198
template <typename FormatContext>
@@ -254,6 +265,16 @@ struct formatter<T>
254265
s.insert(s.begin() + static_cast<std::size_t>(has_sign), static_cast<std::size_t>(padding_digits) - s.size(), '0');
255266
}
256267

268+
if (use_locale)
269+
{
270+
// We need approximately 1/3 more space in order to insert the thousands separators,
271+
// but after we have done our processing we need to shrink the string back down
272+
const auto initial_length {s.length()};
273+
s.resize(s.length() * 4 / 3 + 1);
274+
const auto offset {static_cast<std::size_t>(convert_pointer_pair_to_local_locale(const_cast<char*>(s.data()), s.data() + s.length()))};
275+
s.resize(initial_length + offset);
276+
}
277+
257278
return std::format_to(ctx.out(), "{}", s);
258279
}
259280
};

test/test_format.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,25 @@ void test_cohort_preservation()
246246
}
247247
}
248248

249+
template <typename T>
250+
void test_locale_conversion(const char* locale, const std::string& result)
251+
{
252+
try
253+
{
254+
const std::locale a(locale);
255+
std::locale::global(a);
256+
257+
const T value {112289, -2};
258+
BOOST_TEST_EQ(std::format("{:L.2f}", value), result);
259+
}
260+
// LCOV_EXCL_START
261+
catch (...)
262+
{
263+
std::cerr << "Test not run" << std::endl;
264+
}
265+
// LCOV_EXCL_STOP
266+
}
267+
249268
int main()
250269
{
251270
test_general<decimal32_t>();
@@ -287,6 +306,17 @@ int main()
287306
test_cohort_preservation<decimal64_t>();
288307
test_cohort_preservation<decimal128_t>();
289308

309+
#if !(defined(__GNUC__) && __GNUC__ >= 5 && defined(__APPLE__)) && !defined(BOOST_DECIMAL_QEMU_TEST) && !defined(BOOST_DECIMAL_DISABLE_EXCEPTIONS) && !defined(_MSC_VER)
310+
311+
test_locale_conversion<decimal32_t>("en_US.UTF-8", "1,122.89");
312+
test_locale_conversion<decimal32_t>("de_DE.UTF-8", "1.122,89");
313+
314+
#if (defined(__clang__) && __clang_major__ > 9) || (defined(__GNUC__) && __GNUC__ > 9)
315+
test_locale_conversion<decimal32_t>("fr_FR.UTF-8", "1 122,89");
316+
#endif
317+
318+
#endif
319+
290320
return boost::report_errors();
291321
}
292322

0 commit comments

Comments
 (0)