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
#endif
#ifndef FMT_CONSTEXPR
# if FMT_HAS_FEATURE(cxx_constexpr)
# define FMT_CONSTEXPR constexpr
# else
# define FMT_CONSTEXPR
# endif
#endif
#ifndef FMT_OVERRIDE
# if FMT_HAS_FEATURE(cxx_override) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
@ -141,10 +149,10 @@ class basic_string_view {
using char_type = 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. */
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) {}
/**
@ -162,7 +170,7 @@ class basic_string_view {
\endrst
*/
template <typename Alloc>
constexpr basic_string_view(
FMT_CONSTEXPR basic_string_view(
const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT
: data_(s.c_str()), size_(s.size()) {}
@ -179,12 +187,12 @@ class basic_string_view {
const Char *data() const { return data_; }
/** 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_; }
constexpr iterator end() const { return data_ + size_; }
FMT_CONSTEXPR iterator begin() const { return data_; }
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;
size_ -= n;
}
@ -338,8 +346,8 @@ template <typename T>
inline T const_check(T value) { return value; }
struct error_handler {
constexpr error_handler() {}
constexpr error_handler(const error_handler &) {}
FMT_CONSTEXPR error_handler() {}
FMT_CONSTEXPR error_handler(const error_handler &) {}
// This function is intentionally not constexpr to give a compile-time error.
void on_error(const char *message);
@ -377,12 +385,12 @@ enum type {
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");
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");
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(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>
struct string_value {
const Char *value;
@ -511,118 +443,40 @@ class value {
custom_value<Context> custom;
};
constexpr value() : int_value(0) {}
value(bool val) { set<BOOL>(int_value, val); }
value(short val) { set<INT>(int_value, val); }
value(unsigned short val) { set<UINT>(uint_value, val); }
constexpr value(int val) : int_value(val) {}
value(unsigned val) { set<UINT>(uint_value, val); }
value(long val) {
// 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.
if (const_check(sizeof(val) == sizeof(int)))
int_value = static_cast<int>(val);
else
long_long_value = val;
FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
value(unsigned val) { uint_value = val; }
value(long long val) { long_long_value = val; }
value(unsigned long long val) { ulong_long_value = val; }
value(double val) { double_value = val; }
value(long double val) { long_double_value = val; }
value(const char_type *val) { string.value = val; }
value(const signed char *val) {
static_assert(std::is_same<char, char_type>::value,
"incompatible string types");
sstring.value = val;
}
value(unsigned long val) {
if (const_check(sizeof(val) == sizeof(unsigned)))
uint_value = static_cast<unsigned>(val);
else
ulong_long_value = val;
value(const unsigned char *val) {
static_assert(std::is_same<char, char_type>::value,
"incompatible string types");
ustring.value = val;
}
value(long long val) { set<LONG_LONG>(long_long_value, val); }
value(unsigned long long val) { set<ULONG_LONG>(ulong_long_value, val); }
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);
value(basic_string_view<char_type> val) {
string.value = val.data();
string.size = val.size();
}
#endif
// 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); }
value(const void *val) { pointer = val; }
template <typename T>
value(T *p) { set_pointer(p); }
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");
explicit value(const T &val) {
custom.value = &val;
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() {
return *static_cast<const named_arg_base<char_type>*>(pointer);
}
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.
template <typename T>
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.
enum { MAX_PACKED_ARGS = 15 };
@ -652,10 +597,10 @@ class basic_arg {
internal::type type_;
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>
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);
friend class basic_format_args<Context>;
@ -674,7 +619,7 @@ class basic_arg {
internal::custom_value<Context> custom_;
};
constexpr basic_arg() : type_(internal::NONE) {}
FMT_CONSTEXPR basic_arg() : type_(internal::NONE) {}
explicit operator bool() const FMT_NOEXCEPT {
return type_ != internal::NONE;
@ -699,26 +644,28 @@ class basic_parse_context : private ErrorHandler {
using char_type = Char;
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())
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
// Returns an iterator to the beginning of the format string range being
// 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.
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``.
constexpr void advance_to(iterator it) {
FMT_CONSTEXPR void advance_to(iterator it) {
format_str_.remove_prefix(it - begin());
}
// 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) {
on_error("cannot switch from automatic to manual argument indexing");
return false;
@ -728,37 +675,17 @@ class basic_parse_context : private ErrorHandler {
}
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);
}
constexpr ErrorHandler error_handler() const { return *this; }
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
};
using parse_context = basic_parse_context<char>;
using wparse_context = basic_parse_context<wchar_t>;
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.
template <typename Context>
class arg_map {
@ -920,10 +847,47 @@ class basic_context :
format_arg get_arg(basic_string_view<char_type> name);
};
using context = basic_context<
std::back_insert_iterator<internal::buffer>, char>;
using wcontext = basic_context<
std::back_insert_iterator<internal::wbuffer>, wchar_t>;
template <typename Char>
using buffer_context_t = basic_context<
std::back_insert_iterator<internal::basic_buffer<Char>>, Char>;
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>
class arg_store {
@ -940,8 +904,7 @@ class arg_store {
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
public:
static const uint64_t TYPES = IS_PACKED ?
internal::get_types<Args..., void>() : -static_cast<int64_t>(NUM_ARGS);
static const uint64_t TYPES;
arg_store(const Args &... args)
: data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
@ -951,6 +914,11 @@ class arg_store {
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>
inline arg_store<Context, Args...> make_args(const Args & ... args) {
return arg_store<Context, Args...>(args...);

View File

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

View File

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

View File

@ -459,7 +459,8 @@ struct custom_context {
TEST(UtilTest, MakeValueWithCustomFormatter) {
::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};
arg.custom.format(&t, ctx);
EXPECT_TRUE(ctx.called);