Conditionally compile constexpr

This commit is contained in:
Victor Zverovich
2018-02-03 06:14:10 -08:00
parent 5d8ba816de
commit dc5403612e
5 changed files with 403 additions and 422 deletions

View File

@ -42,6 +42,14 @@
# define FMT_MSC_VER 0 # define FMT_MSC_VER 0
#endif #endif
#ifndef FMT_CONSTEXPR
# if FMT_HAS_FEATURE(cxx_constexpr)
# define FMT_CONSTEXPR constexpr
# else
# define FMT_CONSTEXPR
# endif
#endif
#ifndef FMT_OVERRIDE #ifndef FMT_OVERRIDE
# if FMT_HAS_FEATURE(cxx_override) || \ # if FMT_HAS_FEATURE(cxx_override) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
@ -141,10 +149,10 @@ class basic_string_view {
using char_type = Char; using char_type = Char;
using iterator = const Char *; using iterator = const Char *;
constexpr basic_string_view() FMT_NOEXCEPT : data_(0), size_(0) {} FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(0), size_(0) {}
/** Constructs a string reference object from a C string and a size. */ /** Constructs a string reference object from a C string and a size. */
constexpr basic_string_view(const Char *s, size_t size) FMT_NOEXCEPT FMT_CONSTEXPR basic_string_view(const Char *s, size_t size) FMT_NOEXCEPT
: data_(s), size_(size) {} : data_(s), size_(size) {}
/** /**
@ -162,7 +170,7 @@ class basic_string_view {
\endrst \endrst
*/ */
template <typename Alloc> template <typename Alloc>
constexpr basic_string_view( FMT_CONSTEXPR basic_string_view(
const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT
: data_(s.c_str()), size_(s.size()) {} : data_(s.c_str()), size_(s.size()) {}
@ -179,12 +187,12 @@ class basic_string_view {
const Char *data() const { return data_; } const Char *data() const { return data_; }
/** Returns the string size. */ /** Returns the string size. */
constexpr size_t size() const { return size_; } FMT_CONSTEXPR size_t size() const { return size_; }
constexpr iterator begin() const { return data_; } FMT_CONSTEXPR iterator begin() const { return data_; }
constexpr iterator end() const { return data_ + size_; } FMT_CONSTEXPR iterator end() const { return data_ + size_; }
constexpr void remove_prefix(size_t n) { FMT_CONSTEXPR void remove_prefix(size_t n) {
data_ += n; data_ += n;
size_ -= n; size_ -= n;
} }
@ -338,8 +346,8 @@ template <typename T>
inline T const_check(T value) { return value; } inline T const_check(T value) { return value; }
struct error_handler { struct error_handler {
constexpr error_handler() {} FMT_CONSTEXPR error_handler() {}
constexpr error_handler(const error_handler &) {} FMT_CONSTEXPR error_handler(const error_handler &) {}
// This function is intentionally not constexpr to give a compile-time error. // This function is intentionally not constexpr to give a compile-time error.
void on_error(const char *message); void on_error(const char *message);
@ -377,12 +385,12 @@ enum type {
CSTRING, STRING, POINTER, CUSTOM CSTRING, STRING, POINTER, CUSTOM
}; };
constexpr bool is_integral(type t) { FMT_CONSTEXPR bool is_integral(type t) {
FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type");
return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE; return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE;
} }
constexpr bool is_arithmetic(type t) { FMT_CONSTEXPR bool is_arithmetic(type t) {
FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type");
return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE; return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE;
} }
@ -403,82 +411,6 @@ FMT_DISABLE_CONVERSION_TO_INT(float);
FMT_DISABLE_CONVERSION_TO_INT(double); FMT_DISABLE_CONVERSION_TO_INT(double);
FMT_DISABLE_CONVERSION_TO_INT(long double); FMT_DISABLE_CONVERSION_TO_INT(long double);
// Disambiguates conversions to different integral types.
struct type_selector {
static int convert(...);
static int convert(int);
static unsigned convert(unsigned);
static long convert(long);
static unsigned long convert(unsigned long);
static long long convert(long long);
static unsigned long long convert(unsigned long long);
template <typename T>
static constexpr type select() {
return sizeof(convert(std::declval<T>())) == sizeof(int) ? INT : LONG_LONG;
}
};
template <typename T>
constexpr type get_type() {
return std::is_reference<T>::value || std::is_array<T>::value ?
get_type<typename std::decay<T>::type>() :
(is_named_arg<T>::value ?
NAMED_ARG : (convert_to_int<T>::value ?
type_selector::select<T>() : CUSTOM));
}
template <> constexpr type get_type<bool>() { return BOOL; }
template <> constexpr type get_type<short>() { return INT; }
template <> constexpr type get_type<unsigned short>() { return UINT; }
template <> constexpr type get_type<int>() { return INT; }
template <> constexpr type get_type<unsigned>() { return UINT; }
template <> constexpr type get_type<long>() {
return sizeof(long) == sizeof(int) ? INT : LONG_LONG;
}
template <> constexpr type get_type<unsigned long>() {
return sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG;
}
template <> constexpr type get_type<long long>() { return LONG_LONG; }
template <> constexpr type get_type<unsigned long long>() { return ULONG_LONG; }
template <> constexpr type get_type<float>() { return DOUBLE; }
template <> constexpr type get_type<double>() { return DOUBLE; }
template <> constexpr type get_type<long double>() { return LONG_DOUBLE; }
template <> constexpr type get_type<signed char>() { return INT; }
template <> constexpr type get_type<unsigned char>() { return UINT; }
template <> constexpr type get_type<char>() { return CHAR; }
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <> constexpr type get_type<wchar_t>() { return CHAR; }
#endif
template <> constexpr type get_type<char *>() { return CSTRING; }
template <> constexpr type get_type<const char *>() { return CSTRING; }
template <> constexpr type get_type<signed char *>() { return CSTRING; }
template <> constexpr type get_type<const signed char *>() { return CSTRING; }
template <> constexpr type get_type<unsigned char *>() { return CSTRING; }
template <> constexpr type get_type<const unsigned char *>() { return CSTRING; }
template <> constexpr type get_type<std::string>() { return STRING; }
template <> constexpr type get_type<string_view>() { return STRING; }
template <> constexpr type get_type<wchar_t *>() { return CSTRING; }
template <> constexpr type get_type<const wchar_t *>() { return CSTRING; }
template <> constexpr type get_type<std::wstring>() { return STRING; }
template <> constexpr type get_type<wstring_view>() { return STRING; }
template <> constexpr type get_type<void *>() { return POINTER; }
template <> constexpr type get_type<const void *>() { return POINTER; }
template <> constexpr type get_type<std::nullptr_t>() { return POINTER; }
template <typename Arg, typename... Args>
constexpr uint64_t get_types() {
return get_type<Arg>() | (get_types<Args...>() << 4);
}
template <>
constexpr uint64_t get_types<void>() { return 0; }
template <typename Context, typename T>
constexpr basic_arg<Context> make_arg(const T &value);
template <typename Char> template <typename Char>
struct string_value { struct string_value {
const Char *value; const Char *value;
@ -511,118 +443,40 @@ class value {
custom_value<Context> custom; custom_value<Context> custom;
}; };
constexpr value() : int_value(0) {} FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
value(bool val) { set<BOOL>(int_value, val); } value(unsigned val) { uint_value = val; }
value(short val) { set<INT>(int_value, val); } value(long long val) { long_long_value = val; }
value(unsigned short val) { set<UINT>(uint_value, val); } value(unsigned long long val) { ulong_long_value = val; }
constexpr value(int val) : int_value(val) {} value(double val) { double_value = val; }
value(unsigned val) { set<UINT>(uint_value, val); } value(long double val) { long_double_value = val; }
value(const char_type *val) { string.value = val; }
value(long val) { value(const signed char *val) {
// To minimize the number of types we need to deal with, long is static_assert(std::is_same<char, char_type>::value,
// translated either to int or to long long depending on its size. "incompatible string types");
if (const_check(sizeof(val) == sizeof(int))) sstring.value = val;
int_value = static_cast<int>(val);
else
long_long_value = val;
} }
value(const unsigned char *val) {
value(unsigned long val) { static_assert(std::is_same<char, char_type>::value,
if (const_check(sizeof(val) == sizeof(unsigned))) "incompatible string types");
uint_value = static_cast<unsigned>(val); ustring.value = val;
else
ulong_long_value = val;
} }
value(basic_string_view<char_type> val) {
value(long long val) { set<LONG_LONG>(long_long_value, val); } string.value = val.data();
value(unsigned long long val) { set<ULONG_LONG>(ulong_long_value, val); } string.size = val.size();
value(float val) { set<DOUBLE>(double_value, val); }
value(double val) { set<DOUBLE>(double_value, val); }
value(long double val) { set<LONG_DOUBLE>(long_double_value, val); }
value(signed char val) { set<INT>(int_value, val); }
value(unsigned char val) { set<UINT>(uint_value, val); }
value(char val) { set<CHAR>(int_value, val); }
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
value(wchar_t val) {
require_wchar<char_type>();
set<CHAR>(int_value, val);
} }
#endif value(const void *val) { pointer = val; }
// Formatting of wide strings into a narrow buffer and multibyte strings
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
value(char_type *s) { set<CSTRING>(string.value, s); }
value(const char_type *s) { set<CSTRING>(string.value, s); }
value(signed char *s) { set_cstring(sstring.value, s); }
value(const signed char *s) { set_cstring(sstring.value, s); }
value(unsigned char *s) { set_cstring(ustring.value, s); }
value(const unsigned char *s) { set_cstring(ustring.value, s); }
value(basic_string_view<char_type> s) { set_string(s); }
value(const std::basic_string<char_type> &s) { set_string(s); }
template <typename T> template <typename T>
value(T *p) { set_pointer(p); } explicit value(const T &val) {
template <typename T>
value(const T *p) { set_pointer(p); }
value(std::nullptr_t) { pointer = nullptr; }
template <typename T>
value(const T &val,
typename std::enable_if<!convert_to_int<T>::value, int>::type = 0) {
static_assert(get_type<T>() == CUSTOM, "invalid type");
custom.value = &val; custom.value = &val;
custom.format = &format_custom_arg<T>; custom.format = &format_custom_arg<T>;
} }
template <typename T>
value(const named_arg<T, char_type> &val) {
static_assert(get_type<const named_arg<T, char_type> &>() == NAMED_ARG,
"invalid type");
basic_arg<Context> arg = make_arg<Context>(val.value);
std::memcpy(val.data, &arg, sizeof(arg));
pointer = &val;
}
const named_arg_base<char_type> &as_named_arg() { const named_arg_base<char_type> &as_named_arg() {
return *static_cast<const named_arg_base<char_type>*>(pointer); return *static_cast<const named_arg_base<char_type>*>(pointer);
} }
private: private:
template <type TYPE, typename T, typename U>
constexpr void set(T &field, const U &val) {
static_assert(get_type<U>() == TYPE, "invalid type");
field = val;
}
template <typename T>
void set_string(const T &val) {
static_assert(get_type<T>() == STRING, "invalid type");
string.value = val.data();
string.size = val.size();
}
template <typename T, typename U>
constexpr void set_cstring(T &field, const U *str) {
static_assert(std::is_same<char, char_type>::value,
"incompatible string types");
set<CSTRING>(field, str);
}
// Formatting of arbitrary pointers is disallowed. If you want to output a
// pointer cast it to "void *" or "const void *". In particular, this forbids
// formatting of "[const] volatile char *" which is printed as bool by
// iostreams.
template <typename T>
void set_pointer(T *p) {
using nonconst_type = typename std::remove_const<T>::type;
static_assert(std::is_same<nonconst_type, void>::value,
"formatting of non-void pointers is disallowed");
set<POINTER>(pointer, p);
}
// Formats an argument of a custom type, such as a user-defined class. // Formats an argument of a custom type, such as a user-defined class.
template <typename T> template <typename T>
static void format_custom_arg(const void *arg, Context &ctx) { static void format_custom_arg(const void *arg, Context &ctx) {
@ -636,6 +490,97 @@ class value {
} }
}; };
template <typename Context, type TYPE>
struct typed_value : value<Context> {
static const type type_tag = TYPE;
template <typename T>
FMT_CONSTEXPR typed_value(const T &val) : value<Context>(val) {}
};
template <typename Context, typename T>
FMT_CONSTEXPR basic_arg<Context> make_arg(const T &value);
#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \
template <typename C, typename char_type = typename C::char_type> \
FMT_CONSTEXPR typed_value<C, TAG> make_value(ArgType val) { \
return static_cast<ValueType>(val); \
}
FMT_MAKE_VALUE(BOOL, bool, int)
FMT_MAKE_VALUE(INT, short, int)
FMT_MAKE_VALUE(UINT, unsigned short, unsigned)
FMT_MAKE_VALUE(INT, int, int)
FMT_MAKE_VALUE(UINT, unsigned, unsigned)
// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
using long_type =
std::conditional<sizeof(long) == sizeof(int), int, long long>::type;
FMT_MAKE_VALUE(sizeof(long) == sizeof(int) ? INT : LONG_LONG, long, long_type);
using ulong_type =
std::conditional<sizeof(unsigned long) == sizeof(unsigned),
unsigned, unsigned long long>::type;
FMT_MAKE_VALUE(sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG,
unsigned long, ulong_type)
FMT_MAKE_VALUE(LONG_LONG, long long, long long)
FMT_MAKE_VALUE(ULONG_LONG, unsigned long long, unsigned long long)
FMT_MAKE_VALUE(INT, signed char, int)
FMT_MAKE_VALUE(UINT, unsigned char, unsigned)
FMT_MAKE_VALUE(CHAR, char, int)
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template <typename C>
inline typed_value<C, CHAR> make_value(wchar_t val) {
require_wchar<typename C::char_type>();
return static_cast<int>(val);
}
#endif
FMT_MAKE_VALUE(DOUBLE, float, double)
FMT_MAKE_VALUE(DOUBLE, double, double)
FMT_MAKE_VALUE(LONG_DOUBLE, long double, long double)
// Formatting of wide strings into a narrow buffer and multibyte strings
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
FMT_MAKE_VALUE(CSTRING, char_type*, const char_type*)
FMT_MAKE_VALUE(CSTRING, const char_type*, const char_type*)
FMT_MAKE_VALUE(CSTRING, signed char*, const signed char*)
FMT_MAKE_VALUE(CSTRING, const signed char*, const signed char*)
FMT_MAKE_VALUE(CSTRING, unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(CSTRING, const unsigned char*, const unsigned char*)
FMT_MAKE_VALUE(STRING, basic_string_view<char_type>,
basic_string_view<char_type>)
FMT_MAKE_VALUE(STRING, const std::basic_string<char_type>&,
basic_string_view<char_type>)
FMT_MAKE_VALUE(POINTER, void*, const void*)
FMT_MAKE_VALUE(POINTER, const void*, const void*)
FMT_MAKE_VALUE(POINTER, std::nullptr_t, const void*)
// Formatting of arbitrary pointers is disallowed. If you want to output a
// pointer cast it to "void *" or "const void *". In particular, this forbids
// formatting of "[const] volatile char *" which is printed as bool by
// iostreams.
template <typename T>
void make_value(const T *p) {
static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
}
template <typename C, typename T>
inline typename std::enable_if<
!convert_to_int<T>::value, typed_value<C, CUSTOM>>::type
make_value(const T &val) { return val; }
template <typename C, typename T>
typed_value<C, NAMED_ARG>
make_value(const named_arg<T, typename C::char_type> &val) {
basic_arg<C> arg = make_arg<C>(val.value);
std::memcpy(val.data, &arg, sizeof(arg));
return static_cast<const void*>(&val);
}
// Maximum number of arguments with packed types. // Maximum number of arguments with packed types.
enum { MAX_PACKED_ARGS = 15 }; enum { MAX_PACKED_ARGS = 15 };
@ -652,10 +597,10 @@ class basic_arg {
internal::type type_; internal::type type_;
template <typename ContextType, typename T> template <typename ContextType, typename T>
friend constexpr basic_arg<ContextType> internal::make_arg(const T &value); friend FMT_CONSTEXPR basic_arg<ContextType> internal::make_arg(const T &value);
template <typename Visitor, typename Ctx> template <typename Visitor, typename Ctx>
friend constexpr typename std::result_of<Visitor(int)>::type friend FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
visit(Visitor &&vis, basic_arg<Ctx> arg); visit(Visitor &&vis, basic_arg<Ctx> arg);
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
@ -674,7 +619,7 @@ class basic_arg {
internal::custom_value<Context> custom_; internal::custom_value<Context> custom_;
}; };
constexpr basic_arg() : type_(internal::NONE) {} FMT_CONSTEXPR basic_arg() : type_(internal::NONE) {}
explicit operator bool() const FMT_NOEXCEPT { explicit operator bool() const FMT_NOEXCEPT {
return type_ != internal::NONE; return type_ != internal::NONE;
@ -699,26 +644,28 @@ class basic_parse_context : private ErrorHandler {
using char_type = Char; using char_type = Char;
using iterator = typename basic_string_view<Char>::iterator; using iterator = typename basic_string_view<Char>::iterator;
explicit constexpr basic_parse_context( explicit FMT_CONSTEXPR basic_parse_context(
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler()) basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
// Returns an iterator to the beginning of the format string range being // Returns an iterator to the beginning of the format string range being
// parsed. // parsed.
constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); } FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
return format_str_.begin();
}
// Returns an iterator past the end of the format string range being parsed. // Returns an iterator past the end of the format string range being parsed.
constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); } FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
// Advances the begin iterator to ``it``. // Advances the begin iterator to ``it``.
constexpr void advance_to(iterator it) { FMT_CONSTEXPR void advance_to(iterator it) {
format_str_.remove_prefix(it - begin()); format_str_.remove_prefix(it - begin());
} }
// Returns the next argument index. // Returns the next argument index.
constexpr unsigned next_arg_id(); FMT_CONSTEXPR unsigned next_arg_id();
constexpr bool check_arg_id(unsigned) { FMT_CONSTEXPR bool check_arg_id(unsigned) {
if (next_arg_id_ > 0) { if (next_arg_id_ > 0) {
on_error("cannot switch from automatic to manual argument indexing"); on_error("cannot switch from automatic to manual argument indexing");
return false; return false;
@ -728,37 +675,17 @@ class basic_parse_context : private ErrorHandler {
} }
void check_arg_id(basic_string_view<Char>) {} void check_arg_id(basic_string_view<Char>) {}
constexpr void on_error(const char *message) { FMT_CONSTEXPR void on_error(const char *message) {
ErrorHandler::on_error(message); ErrorHandler::on_error(message);
} }
constexpr ErrorHandler error_handler() const { return *this; } FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
}; };
using parse_context = basic_parse_context<char>; using parse_context = basic_parse_context<char>;
using wparse_context = basic_parse_context<wchar_t>; using wparse_context = basic_parse_context<wchar_t>;
namespace internal { namespace internal {
template <typename Context, typename T>
constexpr basic_arg<Context> make_arg(const T &value) {
basic_arg<Context> arg;
arg.type_ = get_type<T>();
arg.value_ = value;
return arg;
}
template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<IS_PACKED, value<Context>>::type
make_arg(const T &value) {
return {value};
}
template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<!IS_PACKED, basic_arg<Context>>::type
make_arg(const T &value) {
return make_arg<Context>(value);
}
// A map from argument names to their values for named arguments. // A map from argument names to their values for named arguments.
template <typename Context> template <typename Context>
class arg_map { class arg_map {
@ -920,10 +847,47 @@ class basic_context :
format_arg get_arg(basic_string_view<char_type> name); format_arg get_arg(basic_string_view<char_type> name);
}; };
using context = basic_context< template <typename Char>
std::back_insert_iterator<internal::buffer>, char>; using buffer_context_t = basic_context<
using wcontext = basic_context< std::back_insert_iterator<internal::basic_buffer<Char>>, Char>;
std::back_insert_iterator<internal::wbuffer>, wchar_t>; using context = buffer_context_t<char>;
using wcontext = buffer_context_t<wchar_t>;
namespace internal {
template <typename Context, typename T>
FMT_CONSTEXPR type get_type() {
using value_type = decltype(make_value<Context>(std::declval<T>()));
return value_type::type_tag;
}
template <typename Context>
FMT_CONSTEXPR uint64_t get_types() { return 0; }
template <typename Context, typename Arg, typename... Args>
FMT_CONSTEXPR uint64_t get_types() {
return get_type<Context, Arg>() | (get_types<Context, Args...>() << 4);
}
template <typename Context, typename T>
FMT_CONSTEXPR basic_arg<Context> make_arg(const T &value) {
basic_arg<Context> arg;
arg.type_ = get_type<Context, T>();
arg.value_ = make_value<Context>(value);
return arg;
}
template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<IS_PACKED, value<Context>>::type
make_arg(const T &value) {
return make_value<Context>(value);
}
template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<!IS_PACKED, basic_arg<Context>>::type
make_arg(const T &value) {
return make_arg<Context>(value);
}
}
template <typename Context, typename ...Args> template <typename Context, typename ...Args>
class arg_store { class arg_store {
@ -940,8 +904,7 @@ class arg_store {
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)]; value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
public: public:
static const uint64_t TYPES = IS_PACKED ? static const uint64_t TYPES;
internal::get_types<Args..., void>() : -static_cast<int64_t>(NUM_ARGS);
arg_store(const Args &... args) arg_store(const Args &... args)
: data_{internal::make_arg<IS_PACKED, Context>(args)...} {} : data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
@ -951,6 +914,11 @@ class arg_store {
const value_type *data() const { return data_; } const value_type *data() const { return data_; }
}; };
template <typename Context, typename ...Args>
const uint64_t arg_store<Context, Args...>::TYPES = IS_PACKED ?
internal::get_types<Context, Args...>() :
-static_cast<int64_t>(NUM_ARGS);
template <typename Context, typename ...Args> template <typename Context, typename ...Args>
inline arg_store<Context, Args...> make_args(const Args & ... args) { inline arg_store<Context, Args...> make_args(const Args & ... args) {
return arg_store<Context, Args...>(args...); return arg_store<Context, Args...>(args...);

View File

@ -293,7 +293,7 @@ namespace internal {
// Casts nonnegative integer to unsigned. // Casts nonnegative integer to unsigned.
template <typename Int> template <typename Int>
constexpr typename std::make_unsigned<Int>::type to_unsigned(Int value) { FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
FMT_ASSERT(value >= 0, "negative value"); FMT_ASSERT(value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value); return static_cast<typename std::make_unsigned<Int>::type>(value);
} }
@ -561,7 +561,7 @@ template <typename Char>
class null_terminating_iterator; class null_terminating_iterator;
template <typename Char> template <typename Char>
constexpr const Char *pointer_from(null_terminating_iterator<Char> it); FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it);
// An iterator that produces a null terminator on *end. This simplifies parsing // An iterator that produces a null terminator on *end. This simplifies parsing
// and allows comparing the performance of processing a null-terminated string // and allows comparing the performance of processing a null-terminated string
@ -577,11 +577,11 @@ class null_terminating_iterator {
null_terminating_iterator() : ptr_(0), end_(0) {} null_terminating_iterator() : ptr_(0), end_(0) {}
constexpr null_terminating_iterator(const Char *ptr, const Char *end) FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)
: ptr_(ptr), end_(end) {} : ptr_(ptr), end_(end) {}
template <typename Range> template <typename Range>
constexpr explicit null_terminating_iterator(const Range &r) FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
: ptr_(r.begin()), end_(r.end()) {} : ptr_(r.begin()), end_(r.end()) {}
null_terminating_iterator &operator=(const Char *ptr) { null_terminating_iterator &operator=(const Char *ptr) {
@ -590,44 +590,45 @@ class null_terminating_iterator {
return *this; return *this;
} }
constexpr Char operator*() const { FMT_CONSTEXPR Char operator*() const {
return ptr_ != end_ ? *ptr_ : 0; return ptr_ != end_ ? *ptr_ : 0;
} }
constexpr null_terminating_iterator operator++() { FMT_CONSTEXPR null_terminating_iterator operator++() {
++ptr_; ++ptr_;
return *this; return *this;
} }
constexpr null_terminating_iterator operator++(int) { FMT_CONSTEXPR null_terminating_iterator operator++(int) {
null_terminating_iterator result(*this); null_terminating_iterator result(*this);
++ptr_; ++ptr_;
return result; return result;
} }
constexpr null_terminating_iterator operator--() { FMT_CONSTEXPR null_terminating_iterator operator--() {
--ptr_; --ptr_;
return *this; return *this;
} }
constexpr null_terminating_iterator operator+(difference_type n) { FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {
return null_terminating_iterator(ptr_ + n, end_); return null_terminating_iterator(ptr_ + n, end_);
} }
constexpr null_terminating_iterator operator-(difference_type n) { FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {
return null_terminating_iterator(ptr_ - n, end_); return null_terminating_iterator(ptr_ - n, end_);
} }
constexpr null_terminating_iterator operator+=(difference_type n) { FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {
ptr_ += n; ptr_ += n;
return *this; return *this;
} }
constexpr difference_type operator-(null_terminating_iterator other) const { FMT_CONSTEXPR difference_type operator-(
null_terminating_iterator other) const {
return ptr_ - other.ptr_; return ptr_ - other.ptr_;
} }
constexpr bool operator!=(null_terminating_iterator other) const { FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {
return ptr_ != other.ptr_; return ptr_ != other.ptr_;
} }
@ -635,7 +636,8 @@ class null_terminating_iterator {
return ptr_ >= other.ptr_; return ptr_ >= other.ptr_;
} }
friend constexpr const Char *pointer_from<Char>(null_terminating_iterator it); friend FMT_CONSTEXPR const Char *pointer_from<Char>(
null_terminating_iterator it);
private: private:
const Char *ptr_; const Char *ptr_;
@ -643,10 +645,10 @@ class null_terminating_iterator {
}; };
template <typename T> template <typename T>
constexpr const T *pointer_from(const T *p) { return p; } FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }
template <typename Char> template <typename Char>
constexpr const Char *pointer_from(null_terminating_iterator<Char> it) { FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
return it.ptr_; return it.ptr_;
} }
@ -686,12 +688,12 @@ class counting_iterator {
// Returns true if value is negative, false otherwise. // Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template <typename T> template <typename T>
constexpr typename std::enable_if< FMT_CONSTEXPR typename std::enable_if<
std::numeric_limits<T>::is_signed, bool>::type is_negative(T value) { std::numeric_limits<T>::is_signed, bool>::type is_negative(T value) {
return value < 0; return value < 0;
} }
template <typename T> template <typename T>
constexpr typename std::enable_if< FMT_CONSTEXPR typename std::enable_if<
!std::numeric_limits<T>::is_signed, bool>::type is_negative(T) { !std::numeric_limits<T>::is_signed, bool>::type is_negative(T) {
return false; return false;
} }
@ -988,7 +990,7 @@ struct monostate {};
\endrst \endrst
*/ */
template <typename Visitor, typename Context> template <typename Visitor, typename Context>
constexpr typename std::result_of<Visitor(int)>::type FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
visit(Visitor &&vis, basic_arg<Context> arg) { visit(Visitor &&vis, basic_arg<Context> arg) {
using char_type = typename Context::char_type; using char_type = typename Context::char_type;
switch (arg.type_) { switch (arg.type_) {
@ -1071,13 +1073,13 @@ struct align_spec : empty_spec {
wchar_t fill_; wchar_t fill_;
alignment align_; alignment align_;
constexpr align_spec( FMT_CONSTEXPR align_spec(
unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT)
: width_(width), fill_(fill), align_(align) {} : width_(width), fill_(fill), align_(align) {}
constexpr unsigned width() const { return width_; } FMT_CONSTEXPR unsigned width() const { return width_; }
constexpr wchar_t fill() const { return fill_; } FMT_CONSTEXPR wchar_t fill() const { return fill_; }
constexpr alignment align() const { return align_; } FMT_CONSTEXPR alignment align() const { return align_; }
int precision() const { return -1; } int precision() const { return -1; }
}; };
@ -1112,7 +1114,7 @@ class basic_format_specs : public align_spec {
int precision_; int precision_;
Char type_; Char type_;
constexpr basic_format_specs( FMT_CONSTEXPR basic_format_specs(
unsigned width = 0, char type = 0, wchar_t fill = ' ') unsigned width = 0, char type = 0, wchar_t fill = ' ')
: align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {}
@ -1122,15 +1124,15 @@ class basic_format_specs : public align_spec {
set(specs...); set(specs...);
} }
constexpr bool flag(unsigned f) const { return (flags_ & f) != 0; } FMT_CONSTEXPR bool flag(unsigned f) const { return (flags_ & f) != 0; }
constexpr int precision() const { return precision_; } FMT_CONSTEXPR int precision() const { return precision_; }
constexpr Char type() const { return type_; } FMT_CONSTEXPR Char type() const { return type_; }
}; };
typedef basic_format_specs<char> format_specs; typedef basic_format_specs<char> format_specs;
template <typename Char, typename ErrorHandler> template <typename Char, typename ErrorHandler>
constexpr unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() { FMT_CONSTEXPR unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() {
if (next_arg_id_ >= 0) if (next_arg_id_ >= 0)
return internal::to_unsigned(next_arg_id_++); return internal::to_unsigned(next_arg_id_++);
on_error("cannot switch from manual to automatic argument indexing"); on_error("cannot switch from manual to automatic argument indexing");
@ -1140,7 +1142,7 @@ constexpr unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() {
namespace internal { namespace internal {
template <typename Handler> template <typename Handler>
constexpr void handle_int_type_spec(char spec, Handler &&handler) { FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler &&handler) {
switch (spec) { switch (spec) {
case 0: case 'd': case 0: case 'd':
handler.on_dec(); handler.on_dec();
@ -1163,7 +1165,7 @@ constexpr void handle_int_type_spec(char spec, Handler &&handler) {
} }
template <typename Handler> template <typename Handler>
constexpr void handle_float_type_spec(char spec, Handler &&handler) { FMT_CONSTEXPR void handle_float_type_spec(char spec, Handler &&handler) {
switch (spec) { switch (spec) {
case 0: case 'g': case 'G': case 0: case 'g': case 'G':
handler.on_general(); handler.on_general();
@ -1184,7 +1186,7 @@ constexpr void handle_float_type_spec(char spec, Handler &&handler) {
} }
template <typename Char, typename Handler> template <typename Char, typename Handler>
constexpr void handle_char_specs( FMT_CONSTEXPR void handle_char_specs(
const basic_format_specs<Char> &specs, Handler &&handler) { const basic_format_specs<Char> &specs, Handler &&handler) {
if (specs.type() && specs.type() != 'c') { if (specs.type() && specs.type() != 'c') {
handler.on_int(); handler.on_int();
@ -1196,7 +1198,7 @@ constexpr void handle_char_specs(
} }
template <typename Handler> template <typename Handler>
constexpr void handle_cstring_type_spec(char spec, Handler &&handler) { FMT_CONSTEXPR void handle_cstring_type_spec(char spec, Handler &&handler) {
if (spec == 0 || spec == 's') if (spec == 0 || spec == 's')
handler.on_string(); handler.on_string();
else if (spec == 'p') else if (spec == 'p')
@ -1206,13 +1208,13 @@ constexpr void handle_cstring_type_spec(char spec, Handler &&handler) {
} }
template <typename Char, typename ErrorHandler> template <typename Char, typename ErrorHandler>
constexpr void check_string_type_spec(Char spec, ErrorHandler &&eh) { FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler &&eh) {
if (spec != 0 && spec != 's') if (spec != 0 && spec != 's')
eh.on_error("invalid type specifier"); eh.on_error("invalid type specifier");
} }
template <typename ErrorHandler> template <typename ErrorHandler>
constexpr void check_pointer_type_spec(char spec, ErrorHandler &&eh) { FMT_CONSTEXPR void check_pointer_type_spec(char spec, ErrorHandler &&eh) {
if (spec != 0 && spec != 'p') if (spec != 0 && spec != 'p')
eh.on_error("invalid type specifier"); eh.on_error("invalid type specifier");
} }
@ -1220,15 +1222,15 @@ constexpr void check_pointer_type_spec(char spec, ErrorHandler &&eh) {
template <typename ErrorHandler> template <typename ErrorHandler>
class int_type_checker : private ErrorHandler { class int_type_checker : private ErrorHandler {
public: public:
constexpr explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {}
constexpr void on_dec() {} FMT_CONSTEXPR void on_dec() {}
constexpr void on_hex() {} FMT_CONSTEXPR void on_hex() {}
constexpr void on_bin() {} FMT_CONSTEXPR void on_bin() {}
constexpr void on_oct() {} FMT_CONSTEXPR void on_oct() {}
constexpr void on_num() {} FMT_CONSTEXPR void on_num() {}
constexpr void on_error() { FMT_CONSTEXPR void on_error() {
ErrorHandler::on_error("invalid type specifier"); ErrorHandler::on_error("invalid type specifier");
} }
}; };
@ -1236,14 +1238,15 @@ class int_type_checker : private ErrorHandler {
template <typename ErrorHandler> template <typename ErrorHandler>
class float_type_checker : private ErrorHandler { class float_type_checker : private ErrorHandler {
public: public:
constexpr explicit float_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} FMT_CONSTEXPR explicit float_type_checker(ErrorHandler eh)
: ErrorHandler(eh) {}
constexpr void on_general() {} FMT_CONSTEXPR void on_general() {}
constexpr void on_exp() {} FMT_CONSTEXPR void on_exp() {}
constexpr void on_fixed() {} FMT_CONSTEXPR void on_fixed() {}
constexpr void on_hex() {} FMT_CONSTEXPR void on_hex() {}
constexpr void on_error() { FMT_CONSTEXPR void on_error() {
ErrorHandler::on_error("invalid type specifier"); ErrorHandler::on_error("invalid type specifier");
} }
}; };
@ -1254,22 +1257,23 @@ class char_specs_checker : public ErrorHandler {
char type_; char type_;
public: public:
constexpr char_specs_checker(char type, ErrorHandler eh) FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)
: ErrorHandler(eh), type_(type) {} : ErrorHandler(eh), type_(type) {}
constexpr void on_int() { FMT_CONSTEXPR void on_int() {
handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this)); handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this));
} }
constexpr void on_char() {} FMT_CONSTEXPR void on_char() {}
}; };
template <typename ErrorHandler> template <typename ErrorHandler>
class cstring_type_checker : public ErrorHandler { class cstring_type_checker : public ErrorHandler {
public: public:
constexpr explicit cstring_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh)
: ErrorHandler(eh) {}
constexpr void on_string() {} FMT_CONSTEXPR void on_string() {}
constexpr void on_pointer() {} FMT_CONSTEXPR void on_pointer() {}
}; };
template <typename Context> template <typename Context>
@ -1412,7 +1416,7 @@ class arg_formatter_base {
struct format_string {}; struct format_string {};
template <typename Char> template <typename Char>
constexpr bool is_name_start(Char c) { FMT_CONSTEXPR bool is_name_start(Char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
} }
@ -1420,7 +1424,7 @@ constexpr bool is_name_start(Char c) {
// first character is a digit and presence of a non-digit character at the end. // first character is a digit and presence of a non-digit character at the end.
// it: an iterator pointing to the beginning of the input range. // it: an iterator pointing to the beginning of the input range.
template <typename Iterator, typename ErrorHandler> template <typename Iterator, typename ErrorHandler>
constexpr unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) { FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
assert('0' <= *it && *it <= '9'); assert('0' <= *it && *it <= '9');
unsigned value = 0; unsigned value = 0;
// Convert to unsigned to prevent a warning. // Convert to unsigned to prevent a warning.
@ -1471,10 +1475,10 @@ struct is_integer {
template <typename ErrorHandler> template <typename ErrorHandler>
class width_checker { class width_checker {
public: public:
explicit constexpr width_checker(ErrorHandler &eh) : handler_(eh) {} explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {}
template <typename T> template <typename T>
constexpr typename std::enable_if< FMT_CONSTEXPR typename std::enable_if<
is_integer<T>::value, unsigned long long>::type operator()(T value) { is_integer<T>::value, unsigned long long>::type operator()(T value) {
if (is_negative(value)) if (is_negative(value))
handler_.on_error("negative width"); handler_.on_error("negative width");
@ -1482,7 +1486,7 @@ class width_checker {
} }
template <typename T> template <typename T>
constexpr typename std::enable_if< FMT_CONSTEXPR typename std::enable_if<
!is_integer<T>::value, unsigned long long>::type operator()(T) { !is_integer<T>::value, unsigned long long>::type operator()(T) {
handler_.on_error("width is not integer"); handler_.on_error("width is not integer");
return 0; return 0;
@ -1495,10 +1499,10 @@ class width_checker {
template <typename ErrorHandler> template <typename ErrorHandler>
class precision_checker { class precision_checker {
public: public:
explicit constexpr precision_checker(ErrorHandler &eh) : handler_(eh) {} explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {}
template <typename T> template <typename T>
constexpr typename std::enable_if< FMT_CONSTEXPR typename std::enable_if<
is_integer<T>::value, unsigned long long>::type operator()(T value) { is_integer<T>::value, unsigned long long>::type operator()(T value) {
if (is_negative(value)) if (is_negative(value))
handler_.on_error("negative precision"); handler_.on_error("negative precision");
@ -1506,7 +1510,7 @@ class precision_checker {
} }
template <typename T> template <typename T>
constexpr typename std::enable_if< FMT_CONSTEXPR typename std::enable_if<
!is_integer<T>::value, unsigned long long>::type operator()(T) { !is_integer<T>::value, unsigned long long>::type operator()(T) {
handler_.on_error("precision is not integer"); handler_.on_error("precision is not integer");
return 0; return 0;
@ -1520,30 +1524,30 @@ class precision_checker {
template <typename Char> template <typename Char>
class specs_setter { class specs_setter {
public: public:
explicit constexpr specs_setter(basic_format_specs<Char> &specs): explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char> &specs):
specs_(specs) {} specs_(specs) {}
constexpr specs_setter(const specs_setter &other) : specs_(other.specs_) {} FMT_CONSTEXPR specs_setter(const specs_setter &other) : specs_(other.specs_) {}
constexpr void on_align(alignment align) { specs_.align_ = align; } FMT_CONSTEXPR void on_align(alignment align) { specs_.align_ = align; }
constexpr void on_fill(Char fill) { specs_.fill_ = fill; } FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; }
constexpr void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } FMT_CONSTEXPR void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; }
constexpr void on_minus() { specs_.flags_ |= MINUS_FLAG; } FMT_CONSTEXPR void on_minus() { specs_.flags_ |= MINUS_FLAG; }
constexpr void on_space() { specs_.flags_ |= SIGN_FLAG; } FMT_CONSTEXPR void on_space() { specs_.flags_ |= SIGN_FLAG; }
constexpr void on_hash() { specs_.flags_ |= HASH_FLAG; } FMT_CONSTEXPR void on_hash() { specs_.flags_ |= HASH_FLAG; }
constexpr void on_zero() { FMT_CONSTEXPR void on_zero() {
specs_.align_ = ALIGN_NUMERIC; specs_.align_ = ALIGN_NUMERIC;
specs_.fill_ = '0'; specs_.fill_ = '0';
} }
constexpr void on_width(unsigned width) { specs_.width_ = width; } FMT_CONSTEXPR void on_width(unsigned width) { specs_.width_ = width; }
constexpr void on_precision(unsigned precision) { FMT_CONSTEXPR void on_precision(unsigned precision) {
specs_.precision_ = precision; specs_.precision_ = precision;
} }
constexpr void end_precision() {} FMT_CONSTEXPR void end_precision() {}
constexpr void on_type(Char type) { specs_.type_ = type; } FMT_CONSTEXPR void on_type(Char type) { specs_.type_ = type; }
protected: protected:
basic_format_specs<Char> &specs_; basic_format_specs<Char> &specs_;
@ -1554,55 +1558,55 @@ class specs_setter {
template <typename Handler> template <typename Handler>
class specs_checker : public Handler { class specs_checker : public Handler {
public: public:
constexpr specs_checker(const Handler& handler, internal::type arg_type) FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type)
: Handler(handler), arg_type_(arg_type) {} : Handler(handler), arg_type_(arg_type) {}
constexpr specs_checker(const specs_checker &other) FMT_CONSTEXPR specs_checker(const specs_checker &other)
: Handler(other), arg_type_(other.arg_type_) {} : Handler(other), arg_type_(other.arg_type_) {}
constexpr void on_align(alignment align) { FMT_CONSTEXPR void on_align(alignment align) {
if (align == ALIGN_NUMERIC) if (align == ALIGN_NUMERIC)
require_numeric_argument(); require_numeric_argument();
Handler::on_align(align); Handler::on_align(align);
} }
constexpr void on_plus() { FMT_CONSTEXPR void on_plus() {
check_sign(); check_sign();
Handler::on_plus(); Handler::on_plus();
} }
constexpr void on_minus() { FMT_CONSTEXPR void on_minus() {
check_sign(); check_sign();
Handler::on_minus(); Handler::on_minus();
} }
constexpr void on_space() { FMT_CONSTEXPR void on_space() {
check_sign(); check_sign();
Handler::on_space(); Handler::on_space();
} }
constexpr void on_hash() { FMT_CONSTEXPR void on_hash() {
require_numeric_argument(); require_numeric_argument();
Handler::on_hash(); Handler::on_hash();
} }
constexpr void on_zero() { FMT_CONSTEXPR void on_zero() {
require_numeric_argument(); require_numeric_argument();
Handler::on_zero(); Handler::on_zero();
} }
constexpr void end_precision() { FMT_CONSTEXPR void end_precision() {
if (is_integral(arg_type_) || arg_type_ == POINTER) if (is_integral(arg_type_) || arg_type_ == POINTER)
this->on_error("precision not allowed for this argument type"); this->on_error("precision not allowed for this argument type");
} }
private: private:
constexpr void require_numeric_argument() { FMT_CONSTEXPR void require_numeric_argument() {
if (!is_arithmetic(arg_type_)) if (!is_arithmetic(arg_type_))
this->on_error("format specifier requires numeric argument"); this->on_error("format specifier requires numeric argument");
} }
constexpr void check_sign() { FMT_CONSTEXPR void check_sign() {
require_numeric_argument(); require_numeric_argument();
if (is_integral(arg_type_) && arg_type_ != INT && arg_type_ != LONG_LONG && if (is_integral(arg_type_) && arg_type_ != INT && arg_type_ != LONG_LONG &&
arg_type_ != CHAR) { arg_type_ != CHAR) {
@ -1615,7 +1619,7 @@ class specs_checker : public Handler {
template <template <typename> class Handler, typename T, template <template <typename> class Handler, typename T,
typename Context, typename ErrorHandler> typename Context, typename ErrorHandler>
constexpr void set_dynamic_spec( FMT_CONSTEXPR void set_dynamic_spec(
T &value, basic_arg<Context> arg, ErrorHandler eh) { T &value, basic_arg<Context> arg, ErrorHandler eh) {
unsigned long long big_value = visit(Handler<ErrorHandler>(eh), arg); unsigned long long big_value = visit(Handler<ErrorHandler>(eh), arg);
if (big_value > (std::numeric_limits<int>::max)()) if (big_value > (std::numeric_limits<int>::max)())
@ -1631,17 +1635,17 @@ class specs_handler: public specs_setter<typename Context::char_type> {
public: public:
typedef typename Context::char_type char_type; typedef typename Context::char_type char_type;
constexpr specs_handler(basic_format_specs<char_type> &specs, Context &ctx) FMT_CONSTEXPR specs_handler(basic_format_specs<char_type> &specs, Context &ctx)
: specs_setter<char_type>(specs), context_(ctx) {} : specs_setter<char_type>(specs), context_(ctx) {}
template <typename Id> template <typename Id>
constexpr void on_dynamic_width(Id arg_id) { FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
set_dynamic_spec<width_checker>( set_dynamic_spec<width_checker>(
this->specs_.width_, get_arg(arg_id), context_.error_handler()); this->specs_.width_, get_arg(arg_id), context_.error_handler());
} }
template <typename Id> template <typename Id>
constexpr void on_dynamic_precision(Id arg_id) { FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
set_dynamic_spec<precision_checker>( set_dynamic_spec<precision_checker>(
this->specs_.precision_, get_arg(arg_id), context_.error_handler()); this->specs_.precision_, get_arg(arg_id), context_.error_handler());
} }
@ -1651,12 +1655,12 @@ class specs_handler: public specs_setter<typename Context::char_type> {
} }
private: private:
constexpr basic_arg<Context> get_arg(auto_id) { FMT_CONSTEXPR basic_arg<Context> get_arg(auto_id) {
return context_.next_arg(); return context_.next_arg();
} }
template <typename Id> template <typename Id>
constexpr basic_arg<Context> get_arg(Id arg_id) { FMT_CONSTEXPR basic_arg<Context> get_arg(Id arg_id) {
context_.parse_context().check_arg_id(arg_id); context_.parse_context().check_arg_id(arg_id);
return context_.get_arg(arg_id); return context_.get_arg(arg_id);
} }
@ -1669,11 +1673,11 @@ template <typename Char>
struct arg_ref { struct arg_ref {
enum Kind { NONE, INDEX, NAME }; enum Kind { NONE, INDEX, NAME };
constexpr arg_ref() : kind(NONE), index(0) {} FMT_CONSTEXPR arg_ref() : kind(NONE), index(0) {}
constexpr explicit arg_ref(unsigned index) : kind(INDEX), index(index) {} FMT_CONSTEXPR explicit arg_ref(unsigned index) : kind(INDEX), index(index) {}
explicit arg_ref(basic_string_view<Char> name) : kind(NAME), name(name) {} explicit arg_ref(basic_string_view<Char> name) : kind(NAME), name(name) {}
constexpr arg_ref &operator=(unsigned index) { FMT_CONSTEXPR arg_ref &operator=(unsigned index) {
kind = INDEX; kind = INDEX;
this->index = index; this->index = index;
return *this; return *this;
@ -1703,25 +1707,25 @@ class dynamic_specs_handler :
public: public:
using char_type = typename ParseContext::char_type; using char_type = typename ParseContext::char_type;
constexpr dynamic_specs_handler( FMT_CONSTEXPR dynamic_specs_handler(
dynamic_format_specs<char_type> &specs, ParseContext &ctx) dynamic_format_specs<char_type> &specs, ParseContext &ctx)
: specs_setter<char_type>(specs), specs_(specs), context_(ctx) {} : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
constexpr dynamic_specs_handler(const dynamic_specs_handler &other) FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler &other)
: specs_setter<char_type>(other), : specs_setter<char_type>(other),
specs_(other.specs_), context_(other.context_) {} specs_(other.specs_), context_(other.context_) {}
template <typename Id> template <typename Id>
constexpr void on_dynamic_width(Id arg_id) { FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
specs_.width_ref = make_arg_ref(arg_id); specs_.width_ref = make_arg_ref(arg_id);
} }
template <typename Id> template <typename Id>
constexpr void on_dynamic_precision(Id arg_id) { FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
specs_.precision_ref = make_arg_ref(arg_id); specs_.precision_ref = make_arg_ref(arg_id);
} }
constexpr void on_error(const char *message) { FMT_CONSTEXPR void on_error(const char *message) {
context_.on_error(message); context_.on_error(message);
} }
@ -1729,12 +1733,12 @@ class dynamic_specs_handler :
using arg_ref_type = arg_ref<char_type>; using arg_ref_type = arg_ref<char_type>;
template <typename Id> template <typename Id>
constexpr arg_ref_type make_arg_ref(Id arg_id) { FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
context_.check_arg_id(arg_id); context_.check_arg_id(arg_id);
return arg_ref_type(arg_id); return arg_ref_type(arg_id);
} }
constexpr arg_ref_type make_arg_ref(auto_id) { FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) {
return arg_ref_type(context_.next_arg_id()); return arg_ref_type(context_.next_arg_id());
} }
@ -1743,7 +1747,7 @@ class dynamic_specs_handler :
}; };
template <typename Iterator, typename IDHandler> template <typename Iterator, typename IDHandler>
constexpr Iterator parse_arg_id(Iterator it, IDHandler &&handler) { FMT_CONSTEXPR Iterator parse_arg_id(Iterator it, IDHandler &&handler) {
using char_type = typename std::iterator_traits<Iterator>::value_type; using char_type = typename std::iterator_traits<Iterator>::value_type;
char_type c = *it; char_type c = *it;
if (c == '}' || c == ':') { if (c == '}' || c == ':') {
@ -1774,15 +1778,17 @@ constexpr Iterator parse_arg_id(Iterator it, IDHandler &&handler) {
// Adapts SpecHandler to IDHandler API for dynamic width. // Adapts SpecHandler to IDHandler API for dynamic width.
template <typename SpecHandler, typename Char> template <typename SpecHandler, typename Char>
struct width_adapter { struct width_adapter {
explicit constexpr width_adapter(SpecHandler &h) : handler(h) {} explicit FMT_CONSTEXPR width_adapter(SpecHandler &h) : handler(h) {}
constexpr void operator()() { handler.on_dynamic_width(auto_id()); } FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
constexpr void operator()(unsigned id) { handler.on_dynamic_width(id); } FMT_CONSTEXPR void operator()(unsigned id) { handler.on_dynamic_width(id); }
constexpr void operator()(basic_string_view<Char> id) { FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
handler.on_dynamic_width(id); handler.on_dynamic_width(id);
} }
constexpr void on_error(const char *message) { handler.on_error(message); } FMT_CONSTEXPR void on_error(const char *message) {
handler.on_error(message);
}
SpecHandler &handler; SpecHandler &handler;
}; };
@ -1790,15 +1796,17 @@ struct width_adapter {
// Adapts SpecHandler to IDHandler API for dynamic precision. // Adapts SpecHandler to IDHandler API for dynamic precision.
template <typename SpecHandler, typename Char> template <typename SpecHandler, typename Char>
struct precision_adapter { struct precision_adapter {
explicit constexpr precision_adapter(SpecHandler &h) : handler(h) {} explicit FMT_CONSTEXPR precision_adapter(SpecHandler &h) : handler(h) {}
constexpr void operator()() { handler.on_dynamic_precision(auto_id()); } FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
constexpr void operator()(unsigned id) { handler.on_dynamic_precision(id); } FMT_CONSTEXPR void operator()(unsigned id) {
constexpr void operator()(basic_string_view<Char> id) { handler.on_dynamic_precision(id);
}
FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
handler.on_dynamic_precision(id); handler.on_dynamic_precision(id);
} }
constexpr void on_error(const char *message) { handler.on_error(message); } FMT_CONSTEXPR void on_error(const char *message) { handler.on_error(message); }
SpecHandler &handler; SpecHandler &handler;
}; };
@ -1809,7 +1817,7 @@ struct precision_adapter {
// characters, possibly emulated via null_terminating_iterator, representing // characters, possibly emulated via null_terminating_iterator, representing
// format specifiers. // format specifiers.
template <typename Iterator, typename SpecHandler> template <typename Iterator, typename SpecHandler>
constexpr Iterator parse_format_specs(Iterator it, SpecHandler &&handler) { FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
using char_type = typename std::iterator_traits<Iterator>::value_type; using char_type = typename std::iterator_traits<Iterator>::value_type;
// Parse fill and alignment. // Parse fill and alignment.
if (char_type c = *it) { if (char_type c = *it) {
@ -1912,15 +1920,15 @@ constexpr Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
template <typename Handler, typename Char> template <typename Handler, typename Char>
struct id_adapter { struct id_adapter {
constexpr explicit id_adapter(Handler &h): handler(h) {} FMT_CONSTEXPR explicit id_adapter(Handler &h): handler(h) {}
constexpr void operator()() { handler.on_arg_id(); } FMT_CONSTEXPR void operator()() { handler.on_arg_id(); }
constexpr void operator()(unsigned id) { handler.on_arg_id(id); } FMT_CONSTEXPR void operator()(unsigned id) { handler.on_arg_id(id); }
constexpr void operator()(basic_string_view<Char> id) { FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
handler.on_arg_id(id); handler.on_arg_id(id);
} }
constexpr void on_error(const char *message) { FMT_CONSTEXPR void on_error(const char *message) {
handler.on_error(message); handler.on_error(message);
} }
@ -1928,7 +1936,7 @@ struct id_adapter {
}; };
template <typename Iterator, typename Handler> template <typename Iterator, typename Handler>
constexpr void parse_format_string(Iterator it, Handler &&handler) { FMT_CONSTEXPR void parse_format_string(Iterator it, Handler &&handler) {
using char_type = typename std::iterator_traits<Iterator>::value_type; using char_type = typename std::iterator_traits<Iterator>::value_type;
auto start = it; auto start = it;
while (*it) { while (*it) {
@ -1966,7 +1974,7 @@ constexpr void parse_format_string(Iterator it, Handler &&handler) {
} }
template <typename T, typename ParseContext> template <typename T, typename ParseContext>
constexpr const typename ParseContext::char_type * FMT_CONSTEXPR const typename ParseContext::char_type *
parse_format_specs(ParseContext &ctx) { parse_format_specs(ParseContext &ctx) {
formatter<T, typename ParseContext::char_type> f; formatter<T, typename ParseContext::char_type> f;
return f.parse(ctx); return f.parse(ctx);
@ -1975,40 +1983,40 @@ constexpr const typename ParseContext::char_type *
template <typename Char, typename ErrorHandler, typename... Args> template <typename Char, typename ErrorHandler, typename... Args>
class format_string_checker { class format_string_checker {
public: public:
explicit constexpr format_string_checker( explicit FMT_CONSTEXPR format_string_checker(
basic_string_view<Char> format_str, ErrorHandler eh) basic_string_view<Char> format_str, ErrorHandler eh)
: context_(format_str, eh) {} : context_(format_str, eh) {}
constexpr void on_text(const Char *, const Char *) {} FMT_CONSTEXPR void on_text(const Char *, const Char *) {}
constexpr void on_arg_id() { FMT_CONSTEXPR void on_arg_id() {
arg_id_ = context_.next_arg_id(); arg_id_ = context_.next_arg_id();
check_arg_id(); check_arg_id();
} }
constexpr void on_arg_id(unsigned id) { FMT_CONSTEXPR void on_arg_id(unsigned id) {
arg_id_ = id; arg_id_ = id;
context_.check_arg_id(id); context_.check_arg_id(id);
check_arg_id(); check_arg_id();
} }
constexpr void on_arg_id(basic_string_view<Char>) {} FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) {}
constexpr void on_replacement_field(const Char *) {} FMT_CONSTEXPR void on_replacement_field(const Char *) {}
constexpr const Char *on_format_specs(const Char *s) { FMT_CONSTEXPR const Char *on_format_specs(const Char *s) {
context_.advance_to(s); context_.advance_to(s);
return to_unsigned(arg_id_) < NUM_ARGS ? return to_unsigned(arg_id_) < NUM_ARGS ?
parse_funcs_[arg_id_](context_) : s; parse_funcs_[arg_id_](context_) : s;
} }
constexpr void on_error(const char *message) { FMT_CONSTEXPR void on_error(const char *message) {
context_.on_error(message); context_.on_error(message);
} }
private: private:
using parse_context_type = basic_parse_context<Char, ErrorHandler>; using parse_context_type = basic_parse_context<Char, ErrorHandler>;
constexpr static size_t NUM_ARGS = sizeof...(Args); enum { NUM_ARGS = sizeof...(Args) };
constexpr void check_arg_id() { FMT_CONSTEXPR void check_arg_id() {
if (internal::to_unsigned(arg_id_) >= NUM_ARGS) if (internal::to_unsigned(arg_id_) >= NUM_ARGS)
context_.on_error("argument index out of range"); context_.on_error("argument index out of range");
} }
@ -2024,7 +2032,7 @@ class format_string_checker {
}; };
template <typename Char, typename ErrorHandler, typename... Args> template <typename Char, typename ErrorHandler, typename... Args>
constexpr bool check_format_string( FMT_CONSTEXPR bool check_format_string(
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) { basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
format_string_checker<Char, ErrorHandler, Args...> checker(s, eh); format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
parse_format_string(s.begin(), checker); parse_format_string(s.begin(), checker);
@ -2034,8 +2042,9 @@ constexpr bool check_format_string(
// Specifies whether to format T using the standard formatter. // Specifies whether to format T using the standard formatter.
// It is not possible to use get_type in formatter specialization directly // It is not possible to use get_type in formatter specialization directly
// because of a bug in MSVC. // because of a bug in MSVC.
template <typename T> template <typename Context, typename T>
struct format_type : std::integral_constant<bool, get_type<T>() != CUSTOM> {}; struct format_type :
std::integral_constant<bool, get_type<Context, T>() != CUSTOM> {};
// Specifies whether to format enums. // Specifies whether to format enums.
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
@ -2326,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 constexpr unsigned SEP_SIZE = 1; static FMT_CONSTEXPR unsigned 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);
@ -2809,15 +2818,17 @@ inline void format_decimal(char *&buffer, T value) {
// Formatter of objects of type T. // Formatter of objects of type T.
template <typename T, typename Char> template <typename T, typename Char>
struct formatter< struct formatter<
T, Char, typename std::enable_if<internal::format_type<T>::value>::type> { T, Char,
typename std::enable_if<
internal::format_type<buffer_context_t<Char>, T>::value>::type> {
// Parses format specifiers stopping either at the end of the range or at the // Parses format specifiers stopping either at the end of the range or at the
// terminating '}'. // terminating '}'.
template <typename ParseContext> template <typename ParseContext>
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<T>(); auto type = internal::get_type<buffer_context_t<Char>, T>();
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);
@ -2922,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<T>()); checker(null_handler(), internal::get_type<FormatContext, T>());
checker.on_align(specs_.align()); checker.on_align(specs_.align());
if (specs_.flags_ == 0) { if (specs_.flags_ == 0) {
// Do nothing. // Do nothing.
@ -3039,7 +3050,7 @@ inline const void *ptr(const T *p) { return p; }
class fill_spec_factory { class fill_spec_factory {
public: public:
constexpr fill_spec_factory() {} FMT_CONSTEXPR fill_spec_factory() {}
template <typename Char> template <typename Char>
fill_spec<Char> operator=(Char value) const { fill_spec<Char> operator=(Char value) const {
@ -3050,16 +3061,16 @@ class fill_spec_factory {
template <typename FormatSpec> template <typename FormatSpec>
class format_spec_factory { class format_spec_factory {
public: public:
constexpr format_spec_factory() {} FMT_CONSTEXPR format_spec_factory() {}
FormatSpec operator=(typename FormatSpec::value_type value) const { FormatSpec operator=(typename FormatSpec::value_type value) const {
return FormatSpec(value); return FormatSpec(value);
} }
}; };
constexpr fill_spec_factory fill; FMT_CONSTEXPR fill_spec_factory fill;
constexpr format_spec_factory<width_spec> width; FMT_CONSTEXPR format_spec_factory<width_spec> width;
constexpr format_spec_factory<type_spec> type; FMT_CONSTEXPR format_spec_factory<type_spec> type;
template <typename It, typename Char> template <typename It, typename Char>
struct arg_join { struct arg_join {
@ -3205,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) {
constexpr bool invalid_format = FMT_CONSTEXPR 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;
@ -3232,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 {
constexpr Char s[] = {CHARS..., '\0'}; FMT_CONSTEXPR Char s[] = {CHARS..., '\0'};
constexpr bool invalid_format = FMT_CONSTEXPR 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;
@ -3269,7 +3280,7 @@ inline namespace literals {
# if FMT_UDL_TEMPLATE # if FMT_UDL_TEMPLATE
template <typename Char, Char... CHARS> template <typename Char, Char... CHARS>
constexpr internal::udl_formatter<Char, CHARS...> operator""_format() { FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator""_format() {
return {}; return {};
} }
# else # else
@ -3309,8 +3320,8 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
#define FMT_STRING(s) [] { \ #define FMT_STRING(s) [] { \
struct S : fmt::internal::format_string { \ struct S : fmt::internal::format_string { \
static constexpr auto value() { return s; } \ static FMT_CONSTEXPR auto value() { return s; } \
static constexpr size_t size() { return sizeof(s); } \ static FMT_CONSTEXPR size_t size() { return sizeof(s); } \
}; \ }; \
return S{}; \ return S{}; \
}() }()

View File

@ -103,7 +103,8 @@ struct format_enum<T,
// Formats an object of type T that has an overloaded ostream operator<<. // Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char> template <typename T, typename Char>
struct formatter<T, Char, struct formatter<T, Char,
typename std::enable_if<!internal::format_type<T>::value>::type> typename std::enable_if<
!internal::format_type<buffer_context_t<Char>, T>::value>::type>
: formatter<basic_string_view<Char>, Char> { : formatter<basic_string_view<Char>, Char> {
template <typename Context> template <typename Context>

View File

@ -1222,7 +1222,7 @@ namespace fmt {
template <> template <>
struct formatter<Date> { struct formatter<Date> {
template <typename ParseContext> template <typename ParseContext>
constexpr auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin(); auto it = ctx.begin();
if (*it == 'd') if (*it == 'd')
++it; ++it;
@ -1604,22 +1604,22 @@ struct test_arg_id_handler {
unsigned index = 0; unsigned index = 0;
string_view name; string_view name;
constexpr void operator()() { res = EMPTY; } FMT_CONSTEXPR void operator()() { res = EMPTY; }
constexpr void operator()(unsigned index) { FMT_CONSTEXPR void operator()(unsigned index) {
res = INDEX; res = INDEX;
this->index = index; this->index = index;
} }
constexpr void operator()(string_view name) { FMT_CONSTEXPR void operator()(string_view name) {
res = NAME; res = NAME;
this->name = name; this->name = name;
} }
constexpr void on_error(const char *) { res = ERROR; } FMT_CONSTEXPR void on_error(const char *) { res = ERROR; }
}; };
constexpr test_arg_id_handler parse_arg_id(const char* s) { FMT_CONSTEXPR test_arg_id_handler parse_arg_id(const char* s) {
test_arg_id_handler h; test_arg_id_handler h;
fmt::internal::parse_arg_id(s, h); fmt::internal::parse_arg_id(s, h);
return h; return h;
@ -1649,39 +1649,39 @@ struct test_format_specs_handler {
// Workaround for MSVC2017 bug that results in "expression did not evaluate // Workaround for MSVC2017 bug that results in "expression did not evaluate
// to a constant" with compiler-generated copy ctor. // to a constant" with compiler-generated copy ctor.
constexpr test_format_specs_handler() {} FMT_CONSTEXPR test_format_specs_handler() {}
constexpr test_format_specs_handler(const test_format_specs_handler &other) FMT_CONSTEXPR test_format_specs_handler(const test_format_specs_handler &other)
: res(other.res), align(other.align), fill(other.fill), : res(other.res), align(other.align), fill(other.fill),
width(other.width), width_ref(other.width_ref), width(other.width), width_ref(other.width_ref),
precision(other.precision), precision_ref(other.precision_ref), precision(other.precision), precision_ref(other.precision_ref),
type(other.type) {} type(other.type) {}
constexpr void on_align(fmt::alignment align) { this->align = align; } FMT_CONSTEXPR void on_align(fmt::alignment align) { this->align = align; }
constexpr void on_fill(char fill) { this->fill = fill; } FMT_CONSTEXPR void on_fill(char fill) { this->fill = fill; }
constexpr void on_plus() { res = PLUS; } FMT_CONSTEXPR void on_plus() { res = PLUS; }
constexpr void on_minus() { res = MINUS; } FMT_CONSTEXPR void on_minus() { res = MINUS; }
constexpr void on_space() { res = SPACE; } FMT_CONSTEXPR void on_space() { res = SPACE; }
constexpr void on_hash() { res = HASH; } FMT_CONSTEXPR void on_hash() { res = HASH; }
constexpr void on_zero() { res = ZERO; } FMT_CONSTEXPR void on_zero() { res = ZERO; }
constexpr void on_width(unsigned width) { this->width = width; } FMT_CONSTEXPR void on_width(unsigned width) { this->width = width; }
constexpr void on_dynamic_width(fmt::internal::auto_id) {} FMT_CONSTEXPR void on_dynamic_width(fmt::internal::auto_id) {}
constexpr void on_dynamic_width(unsigned index) { width_ref = index; } FMT_CONSTEXPR void on_dynamic_width(unsigned index) { width_ref = index; }
constexpr void on_dynamic_width(string_view) {} FMT_CONSTEXPR void on_dynamic_width(string_view) {}
constexpr void on_precision(unsigned precision) { FMT_CONSTEXPR void on_precision(unsigned precision) {
this->precision = precision; this->precision = precision;
} }
constexpr void on_dynamic_precision(fmt::internal::auto_id) {} FMT_CONSTEXPR void on_dynamic_precision(fmt::internal::auto_id) {}
constexpr void on_dynamic_precision(unsigned index) { precision_ref = index; } FMT_CONSTEXPR void on_dynamic_precision(unsigned index) { precision_ref = index; }
constexpr void on_dynamic_precision(string_view) {} FMT_CONSTEXPR void on_dynamic_precision(string_view) {}
constexpr void end_precision() {} FMT_CONSTEXPR void end_precision() {}
constexpr void on_type(char type) { this->type = type; } FMT_CONSTEXPR void on_type(char type) { this->type = type; }
constexpr void on_error(const char *) { res = ERROR; } FMT_CONSTEXPR void on_error(const char *) { res = ERROR; }
}; };
constexpr test_format_specs_handler parse_test_specs(const char *s) { FMT_CONSTEXPR test_format_specs_handler parse_test_specs(const char *s) {
test_format_specs_handler h; test_format_specs_handler h;
fmt::internal::parse_format_specs(s, h); fmt::internal::parse_format_specs(s, h);
return h; return h;
@ -1707,27 +1707,27 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
struct test_context { struct test_context {
using char_type = char; using char_type = char;
constexpr fmt::basic_arg<test_context> next_arg() { FMT_CONSTEXPR fmt::basic_arg<test_context> next_arg() {
return fmt::internal::make_arg<test_context>(11); return fmt::internal::make_arg<test_context>(11);
} }
template <typename Id> template <typename Id>
constexpr fmt::basic_arg<test_context> get_arg(Id) { FMT_CONSTEXPR fmt::basic_arg<test_context> get_arg(Id) {
return fmt::internal::make_arg<test_context>(22); return fmt::internal::make_arg<test_context>(22);
} }
template <typename Id> template <typename Id>
constexpr void check_arg_id(Id) {} FMT_CONSTEXPR void check_arg_id(Id) {}
constexpr unsigned next_arg_id() { return 33; } FMT_CONSTEXPR unsigned next_arg_id() { return 33; }
void on_error(const char *) {} void on_error(const char *) {}
constexpr test_context &parse_context() { return *this; } FMT_CONSTEXPR test_context &parse_context() { return *this; }
constexpr test_context error_handler() { return *this; } FMT_CONSTEXPR test_context error_handler() { return *this; }
}; };
constexpr fmt::format_specs parse_specs(const char *s) { FMT_CONSTEXPR fmt::format_specs parse_specs(const char *s) {
fmt::format_specs specs; fmt::format_specs specs;
test_context ctx; test_context ctx;
fmt::internal::specs_handler<test_context> h(specs, ctx); fmt::internal::specs_handler<test_context> h(specs, ctx);
@ -1752,7 +1752,7 @@ TEST(FormatTest, ConstexprSpecsHandler) {
static_assert(parse_specs("d").type() == 'd', ""); static_assert(parse_specs("d").type() == 'd', "");
} }
constexpr fmt::internal::dynamic_format_specs<char> FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char>
parse_dynamic_specs(const char *s) { parse_dynamic_specs(const char *s) {
fmt::internal::dynamic_format_specs<char> specs; fmt::internal::dynamic_format_specs<char> specs;
test_context ctx; test_context ctx;
@ -1778,7 +1778,7 @@ TEST(FormatTest, ConstexprDynamicSpecsHandler) {
static_assert(parse_dynamic_specs("d").type() == 'd', ""); static_assert(parse_dynamic_specs("d").type() == 'd', "");
} }
constexpr test_format_specs_handler check_specs(const char *s) { FMT_CONSTEXPR test_format_specs_handler check_specs(const char *s) {
fmt::internal::specs_checker<test_format_specs_handler> fmt::internal::specs_checker<test_format_specs_handler>
checker(test_format_specs_handler(), fmt::internal::DOUBLE); checker(test_format_specs_handler(), fmt::internal::DOUBLE);
parse_format_specs(s, checker); parse_format_specs(s, checker);
@ -1803,23 +1803,23 @@ TEST(FormatTest, ConstexprSpecsChecker) {
} }
struct test_format_string_handler { struct test_format_string_handler {
constexpr void on_text(const char *, const char *) {} FMT_CONSTEXPR void on_text(const char *, const char *) {}
constexpr void on_arg_id() {} FMT_CONSTEXPR void on_arg_id() {}
template <typename T> template <typename T>
constexpr void on_arg_id(T) {} FMT_CONSTEXPR void on_arg_id(T) {}
constexpr void on_replacement_field(const char *) {} FMT_CONSTEXPR void on_replacement_field(const char *) {}
constexpr const char *on_format_specs(const char *s) { return s; } FMT_CONSTEXPR const char *on_format_specs(const char *s) { return s; }
constexpr void on_error(const char *) { error = true; } FMT_CONSTEXPR void on_error(const char *) { error = true; }
bool error = false; bool error = false;
}; };
constexpr bool parse_string(const char *s) { FMT_CONSTEXPR bool parse_string(const char *s) {
test_format_string_handler h; test_format_string_handler h;
fmt::internal::parse_format_string(s, h); fmt::internal::parse_format_string(s, h);
return !h.error; return !h.error;
@ -1843,25 +1843,25 @@ TEST(FormatTest, UdlTemplate) {
struct test_error_handler { struct test_error_handler {
const char *&error; const char *&error;
constexpr test_error_handler(const char *&err): error(err) {} FMT_CONSTEXPR test_error_handler(const char *&err): error(err) {}
constexpr test_error_handler(const test_error_handler &other) FMT_CONSTEXPR test_error_handler(const test_error_handler &other)
: error(other.error) {} : error(other.error) {}
constexpr void on_error(const char *message) { FMT_CONSTEXPR void on_error(const char *message) {
if (!error) if (!error)
error = message; error = message;
} }
}; };
constexpr size_t len(const char *s) { FMT_CONSTEXPR size_t len(const char *s) {
size_t len = 0; size_t len = 0;
while (*s++) while (*s++)
++len; ++len;
return len; return len;
} }
constexpr bool equal(const char *s1, const char *s2) { FMT_CONSTEXPR bool equal(const char *s1, const char *s2) {
if (!s1 || !s2) if (!s1 || !s2)
return s1 == s2; return s1 == s2;
while (*s1 && *s1 == *s2) { while (*s1 && *s1 == *s2) {
@ -1872,7 +1872,7 @@ constexpr bool equal(const char *s1, const char *s2) {
} }
template <typename... Args> template <typename... Args>
constexpr bool test_error(const char *fmt, const char *expected_error) { FMT_CONSTEXPR bool test_error(const char *fmt, const char *expected_error) {
const char *actual_error = nullptr; const char *actual_error = nullptr;
fmt::internal::check_format_string<char, test_error_handler, Args...>( fmt::internal::check_format_string<char, test_error_handler, Args...>(
string_view(fmt, len(fmt)), test_error_handler(actual_error)); string_view(fmt, len(fmt)), test_error_handler(actual_error));

View File

@ -459,7 +459,8 @@ struct custom_context {
TEST(UtilTest, MakeValueWithCustomFormatter) { TEST(UtilTest, MakeValueWithCustomFormatter) {
::Test t; ::Test t;
fmt::internal::value<custom_context> arg(t); fmt::internal::value<custom_context> arg =
fmt::internal::make_value<custom_context>(t);
custom_context ctx = {false}; custom_context ctx = {false};
arg.custom.format(&t, ctx); arg.custom.format(&t, ctx);
EXPECT_TRUE(ctx.called); EXPECT_TRUE(ctx.called);