Commit 1f57243b authored by Victor Zverovich's avatar Victor Zverovich

Relax constexpr requirements

parent dc540361
...@@ -42,12 +42,18 @@ ...@@ -42,12 +42,18 @@
# define FMT_MSC_VER 0 # define FMT_MSC_VER 0
#endif #endif
#ifndef FMT_CONSTEXPR // Check if relaxed c++14 constexpr is supported.
# if FMT_HAS_FEATURE(cxx_constexpr) #ifndef FMT_USE_CONSTEXPR
# define FMT_CONSTEXPR constexpr # define FMT_USE_CONSTEXPR \
# else (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_GCC_VERSION >= 500 || \
# define FMT_CONSTEXPR FMT_MSC_VER >= 1910)
# endif #endif
#if FMT_USE_CONSTEXPR
# define FMT_CONSTEXPR constexpr
# define FMT_CONSTEXPR_VAR constexpr
#else
# define FMT_CONSTEXPR inline
# define FMT_CONSTEXPR_VAR
#endif #endif
#ifndef FMT_OVERRIDE #ifndef FMT_OVERRIDE
...@@ -855,23 +861,23 @@ using wcontext = buffer_context_t<wchar_t>; ...@@ -855,23 +861,23 @@ using wcontext = buffer_context_t<wchar_t>;
namespace internal { namespace internal {
template <typename Context, typename T> template <typename Context, typename T>
FMT_CONSTEXPR type get_type() { struct get_type {
using value_type = decltype(make_value<Context>(std::declval<T>())); using value_type = decltype(make_value<Context>(std::declval<T>()));
return value_type::type_tag; static const type value = value_type::type_tag;
} };
template <typename Context> template <typename Context>
FMT_CONSTEXPR uint64_t get_types() { return 0; } FMT_CONSTEXPR uint64_t get_types() { return 0; }
template <typename Context, typename Arg, typename... Args> template <typename Context, typename Arg, typename... Args>
FMT_CONSTEXPR uint64_t get_types() { FMT_CONSTEXPR uint64_t get_types() {
return get_type<Context, Arg>() | (get_types<Context, Args...>() << 4); return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
} }
template <typename Context, typename T> template <typename Context, typename T>
FMT_CONSTEXPR basic_arg<Context> make_arg(const T &value) { FMT_CONSTEXPR basic_arg<Context> make_arg(const T &value) {
basic_arg<Context> arg; basic_arg<Context> arg;
arg.type_ = get_type<Context, T>(); arg.type_ = get_type<Context, T>::value;
arg.value_ = make_value<Context>(value); arg.value_ = make_value<Context>(value);
return arg; return arg;
} }
......
...@@ -2044,7 +2044,7 @@ FMT_CONSTEXPR bool check_format_string( ...@@ -2044,7 +2044,7 @@ FMT_CONSTEXPR bool check_format_string(
// because of a bug in MSVC. // because of a bug in MSVC.
template <typename Context, typename T> template <typename Context, typename T>
struct format_type : struct format_type :
std::integral_constant<bool, get_type<Context, T>() != CUSTOM> {}; std::integral_constant<bool, get_type<Context, T>::value != CUSTOM> {};
// Specifies whether to format enums. // Specifies whether to format enums.
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
...@@ -2335,7 +2335,7 @@ class basic_writer { ...@@ -2335,7 +2335,7 @@ class basic_writer {
void on_num() { void on_num() {
unsigned num_digits = internal::count_digits(abs_value); unsigned num_digits = internal::count_digits(abs_value);
char_type sep = internal::thousands_sep<char_type>(writer.locale_.get()); char_type sep = internal::thousands_sep<char_type>(writer.locale_.get());
static FMT_CONSTEXPR unsigned SEP_SIZE = 1; enum { SEP_SIZE = 1 };
unsigned size = num_digits + SEP_SIZE * ((num_digits - 1) / 3); unsigned size = num_digits + SEP_SIZE * ((num_digits - 1) / 3);
writer.write_int(size, get_prefix(), spec, [this, size, sep](auto &&it) { writer.write_int(size, get_prefix(), spec, [this, size, sep](auto &&it) {
basic_string_view<char_type> s(&sep, SEP_SIZE); basic_string_view<char_type> s(&sep, SEP_SIZE);
...@@ -2828,7 +2828,7 @@ struct formatter< ...@@ -2828,7 +2828,7 @@ struct formatter<
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext &ctx) { FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext &ctx) {
auto it = internal::null_terminating_iterator<Char>(ctx); auto it = internal::null_terminating_iterator<Char>(ctx);
using handler_type = internal::dynamic_specs_handler<ParseContext>; using handler_type = internal::dynamic_specs_handler<ParseContext>;
auto type = internal::get_type<buffer_context_t<Char>, T>(); auto type = internal::get_type<buffer_context_t<Char>, T>::value;
internal::specs_checker<handler_type> internal::specs_checker<handler_type>
handler(handler_type(specs_, ctx), type); handler(handler_type(specs_, ctx), type);
it = parse_format_specs(it, handler); it = parse_format_specs(it, handler);
...@@ -2933,7 +2933,7 @@ struct dynamic_formatter { ...@@ -2933,7 +2933,7 @@ struct dynamic_formatter {
void on_hash() {} void on_hash() {}
}; };
internal::specs_checker<null_handler> internal::specs_checker<null_handler>
checker(null_handler(), internal::get_type<FormatContext, T>()); checker(null_handler(), internal::get_type<FormatContext, T>::value);
checker.on_align(specs_.align()); checker.on_align(specs_.align());
if (specs_.flags_ == 0) { if (specs_.flags_ == 0) {
// Do nothing. // Do nothing.
...@@ -3068,9 +3068,9 @@ class format_spec_factory { ...@@ -3068,9 +3068,9 @@ class format_spec_factory {
} }
}; };
FMT_CONSTEXPR fill_spec_factory fill; static const fill_spec_factory fill;
FMT_CONSTEXPR format_spec_factory<width_spec> width; static const format_spec_factory<width_spec> width;
FMT_CONSTEXPR format_spec_factory<type_spec> type; static const format_spec_factory<type_spec> type;
template <typename It, typename Char> template <typename It, typename Char>
struct arg_join { struct arg_join {
...@@ -3216,7 +3216,7 @@ template <typename String, typename... Args> ...@@ -3216,7 +3216,7 @@ template <typename String, typename... Args>
inline typename std::enable_if< inline typename std::enable_if<
std::is_base_of<internal::format_string, String>::value, std::string>::type std::is_base_of<internal::format_string, String>::value, std::string>::type
format(String format_str, const Args & ... args) { format(String format_str, const Args & ... args) {
FMT_CONSTEXPR bool invalid_format = FMT_CONSTEXPR_VAR bool invalid_format =
internal::check_format_string<char, internal::error_handler, Args...>( internal::check_format_string<char, internal::error_handler, Args...>(
string_view(format_str.value(), format_str.size())); string_view(format_str.value(), format_str.size()));
(void)invalid_format; (void)invalid_format;
...@@ -3243,8 +3243,8 @@ class udl_formatter { ...@@ -3243,8 +3243,8 @@ class udl_formatter {
public: public:
template <typename... Args> template <typename... Args>
std::basic_string<Char> operator()(const Args &... args) const { std::basic_string<Char> operator()(const Args &... args) const {
FMT_CONSTEXPR Char s[] = {CHARS..., '\0'}; FMT_CONSTEXPR_VAR Char s[] = {CHARS..., '\0'};
FMT_CONSTEXPR bool invalid_format = FMT_CONSTEXPR_VAR bool invalid_format =
check_format_string<Char, error_handler, Args...>( check_format_string<Char, error_handler, Args...>(
basic_string_view<Char>(s, sizeof...(CHARS))); basic_string_view<Char>(s, sizeof...(CHARS)));
(void)invalid_format; (void)invalid_format;
......
...@@ -1598,6 +1598,30 @@ TEST(FormatTest, DynamicFormatter) { ...@@ -1598,6 +1598,30 @@ TEST(FormatTest, DynamicFormatter) {
format_error, "precision not allowed for this argument type"); format_error, "precision not allowed for this argument type");
} }
TEST(FormatTest, UdlTemplate) {
EXPECT_EQ("foo", "foo"_format());
EXPECT_EQ(" 42", "{0:10}"_format(42));
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
}
TEST(FormatTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42));
}
TEST(FormatTest, OutputIterators) {
std::list<char> out;
fmt::format_to(std::back_inserter(out), "{}", 42);
EXPECT_EQ("42", std::string(out.begin(), out.end()));
std::stringstream s;
fmt::format_to(std::ostream_iterator<char>(s), "{}", 42);
EXPECT_EQ("42", s.str());
}
TEST(FormatTest, OutputSize) {
EXPECT_EQ(2, fmt::count("{}", 42));
}
#if FMT_USE_CONSTEXPR
struct test_arg_id_handler { struct test_arg_id_handler {
enum result { NONE, EMPTY, INDEX, NAME, ERROR }; enum result { NONE, EMPTY, INDEX, NAME, ERROR };
result res = NONE; result res = NONE;
...@@ -1834,12 +1858,6 @@ TEST(FormatTest, ConstexprParseFormatString) { ...@@ -1834,12 +1858,6 @@ TEST(FormatTest, ConstexprParseFormatString) {
static_assert(parse_string("{:}"), ""); static_assert(parse_string("{:}"), "");
} }
TEST(FormatTest, UdlTemplate) {
EXPECT_EQ("foo", "foo"_format());
EXPECT_EQ(" 42", "{0:10}"_format(42));
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
}
struct test_error_handler { struct test_error_handler {
const char *&error; const char *&error;
...@@ -1936,20 +1954,4 @@ TEST(FormatTest, FormatStringErrors) { ...@@ -1936,20 +1954,4 @@ TEST(FormatTest, FormatStringErrors) {
"cannot switch from automatic to manual argument indexing", "cannot switch from automatic to manual argument indexing",
int, int); int, int);
} }
#endif // FMT_USE_CONSTEXPR
TEST(FormatTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42));
}
TEST(FormatTest, OutputIterators) {
std::list<char> out;
fmt::format_to(std::back_inserter(out), "{}", 42);
EXPECT_EQ("42", std::string(out.begin(), out.end()));
std::stringstream s;
fmt::format_to(std::ostream_iterator<char>(s), "{}", 42);
EXPECT_EQ("42", s.str());
}
TEST(FormatTest, OutputSize) {
EXPECT_EQ(2, fmt::count("{}", 42));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment