From dc5403612e9836d9292aa9be4e69013f3266f56b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 3 Feb 2018 06:14:10 -0800 Subject: [PATCH] Conditionally compile constexpr --- include/fmt/core.h | 412 +++++++++++++++++++----------------------- include/fmt/format.h | 309 ++++++++++++++++--------------- include/fmt/ostream.h | 3 +- test/format-test.cc | 98 +++++----- test/util-test.cc | 3 +- 5 files changed, 403 insertions(+), 422 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 417629bb..e576b6c6 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -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 - constexpr basic_string_view( + FMT_CONSTEXPR basic_string_view( const std::basic_string &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 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 - static constexpr type select() { - return sizeof(convert(std::declval())) == sizeof(int) ? INT : LONG_LONG; - } -}; - -template -constexpr type get_type() { - return std::is_reference::value || std::is_array::value ? - get_type::type>() : - (is_named_arg::value ? - NAMED_ARG : (convert_to_int::value ? - type_selector::select() : CUSTOM)); -} - -template <> constexpr type get_type() { return BOOL; } -template <> constexpr type get_type() { return INT; } -template <> constexpr type get_type() { return UINT; } -template <> constexpr type get_type() { return INT; } -template <> constexpr type get_type() { return UINT; } -template <> constexpr type get_type() { - return sizeof(long) == sizeof(int) ? INT : LONG_LONG; -} -template <> constexpr type get_type() { - return sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG; -} -template <> constexpr type get_type() { return LONG_LONG; } -template <> constexpr type get_type() { return ULONG_LONG; } -template <> constexpr type get_type() { return DOUBLE; } -template <> constexpr type get_type() { return DOUBLE; } -template <> constexpr type get_type() { return LONG_DOUBLE; } -template <> constexpr type get_type() { return INT; } -template <> constexpr type get_type() { return UINT; } -template <> constexpr type get_type() { return CHAR; } - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -template <> constexpr type get_type() { return CHAR; } -#endif - -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return STRING; } -template <> constexpr type get_type() { return STRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return CSTRING; } -template <> constexpr type get_type() { return STRING; } -template <> constexpr type get_type() { return STRING; } -template <> constexpr type get_type() { return POINTER; } -template <> constexpr type get_type() { return POINTER; } -template <> constexpr type get_type() { return POINTER; } - -template -constexpr uint64_t get_types() { - return get_type() | (get_types() << 4); -} - -template <> -constexpr uint64_t get_types() { return 0; } - -template -constexpr basic_arg make_arg(const T &value); - template struct string_value { const Char *value; @@ -511,118 +443,40 @@ class value { custom_value custom; }; - constexpr value() : int_value(0) {} - value(bool val) { set(int_value, val); } - value(short val) { set(int_value, val); } - value(unsigned short val) { set(uint_value, val); } - constexpr value(int val) : int_value(val) {} - value(unsigned val) { set(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(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::value, + "incompatible string types"); + sstring.value = val; } - - value(unsigned long val) { - if (const_check(sizeof(val) == sizeof(unsigned))) - uint_value = static_cast(val); - else - ulong_long_value = val; + value(const unsigned char *val) { + static_assert(std::is_same::value, + "incompatible string types"); + ustring.value = val; } - - value(long long val) { set(long_long_value, val); } - value(unsigned long long val) { set(ulong_long_value, val); } - value(float val) { set(double_value, val); } - value(double val) { set(double_value, val); } - value(long double val) { set(long_double_value, val); } - value(signed char val) { set(int_value, val); } - value(unsigned char val) { set(uint_value, val); } - value(char val) { set(int_value, val); } - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - value(wchar_t val) { - require_wchar(); - set(int_value, val); + value(basic_string_view 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(string.value, s); } - value(const char_type *s) { set(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 s) { set_string(s); } - value(const std::basic_string &s) { set_string(s); } + value(const void *val) { pointer = val; } template - value(T *p) { set_pointer(p); } - - template - value(const T *p) { set_pointer(p); } - - value(std::nullptr_t) { pointer = nullptr; } - - template - value(const T &val, - typename std::enable_if::value, int>::type = 0) { - static_assert(get_type() == CUSTOM, "invalid type"); + explicit value(const T &val) { custom.value = &val; custom.format = &format_custom_arg; } - template - value(const named_arg &val) { - static_assert(get_type &>() == NAMED_ARG, - "invalid type"); - basic_arg arg = make_arg(val.value); - std::memcpy(val.data, &arg, sizeof(arg)); - pointer = &val; - } - const named_arg_base &as_named_arg() { return *static_cast*>(pointer); } private: - template - constexpr void set(T &field, const U &val) { - static_assert(get_type() == TYPE, "invalid type"); - field = val; - } - - template - void set_string(const T &val) { - static_assert(get_type() == STRING, "invalid type"); - string.value = val.data(); - string.size = val.size(); - } - - template - constexpr void set_cstring(T &field, const U *str) { - static_assert(std::is_same::value, - "incompatible string types"); - set(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 - void set_pointer(T *p) { - using nonconst_type = typename std::remove_const::type; - static_assert(std::is_same::value, - "formatting of non-void pointers is disallowed"); - set(pointer, p); - } - // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg(const void *arg, Context &ctx) { @@ -636,6 +490,97 @@ class value { } }; +template +struct typed_value : value { + static const type type_tag = TYPE; + + template + FMT_CONSTEXPR typed_value(const T &val) : value(val) {} +}; + +template +FMT_CONSTEXPR basic_arg make_arg(const T &value); + +#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \ + template \ + FMT_CONSTEXPR typed_value make_value(ArgType val) { \ + return static_cast(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::type; +FMT_MAKE_VALUE(sizeof(long) == sizeof(int) ? INT : LONG_LONG, long, long_type); +using ulong_type = + std::conditional::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 +inline typed_value make_value(wchar_t val) { + require_wchar(); + return static_cast(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, + basic_string_view) +FMT_MAKE_VALUE(STRING, const std::basic_string&, + basic_string_view) +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 +void make_value(const T *p) { + static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); +} + +template +inline typename std::enable_if< + !convert_to_int::value, typed_value>::type + make_value(const T &val) { return val; } + +template +typed_value + make_value(const named_arg &val) { + basic_arg arg = make_arg(val.value); + std::memcpy(val.data, &arg, sizeof(arg)); + return static_cast(&val); +} + // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 15 }; @@ -652,10 +597,10 @@ class basic_arg { internal::type type_; template - friend constexpr basic_arg internal::make_arg(const T &value); + friend FMT_CONSTEXPR basic_arg internal::make_arg(const T &value); template - friend constexpr typename std::result_of::type + friend FMT_CONSTEXPR typename std::result_of::type visit(Visitor &&vis, basic_arg arg); friend class basic_format_args; @@ -674,7 +619,7 @@ class basic_arg { internal::custom_value 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::iterator; - explicit constexpr basic_parse_context( + explicit FMT_CONSTEXPR basic_parse_context( basic_string_view 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) {} - 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; using wparse_context = basic_parse_context; namespace internal { -template -constexpr basic_arg make_arg(const T &value) { - basic_arg arg; - arg.type_ = get_type(); - arg.value_ = value; - return arg; -} - -template -inline typename std::enable_if>::type - make_arg(const T &value) { - return {value}; -} - -template -inline typename std::enable_if>::type - make_arg(const T &value) { - return make_arg(value); -} - // A map from argument names to their values for named arguments. template class arg_map { @@ -920,10 +847,47 @@ class basic_context : format_arg get_arg(basic_string_view name); }; -using context = basic_context< - std::back_insert_iterator, char>; -using wcontext = basic_context< - std::back_insert_iterator, wchar_t>; +template +using buffer_context_t = basic_context< + std::back_insert_iterator>, Char>; +using context = buffer_context_t; +using wcontext = buffer_context_t; + +namespace internal { +template +FMT_CONSTEXPR type get_type() { + using value_type = decltype(make_value(std::declval())); + return value_type::type_tag; +} + +template +FMT_CONSTEXPR uint64_t get_types() { return 0; } + +template +FMT_CONSTEXPR uint64_t get_types() { + return get_type() | (get_types() << 4); +} + +template +FMT_CONSTEXPR basic_arg make_arg(const T &value) { + basic_arg arg; + arg.type_ = get_type(); + arg.value_ = make_value(value); + return arg; +} + +template +inline typename std::enable_if>::type + make_arg(const T &value) { + return make_value(value); +} + +template +inline typename std::enable_if>::type + make_arg(const T &value) { + return make_arg(value); +} +} template 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() : -static_cast(NUM_ARGS); + static const uint64_t TYPES; arg_store(const Args &... args) : data_{internal::make_arg(args)...} {} @@ -951,6 +914,11 @@ class arg_store { const value_type *data() const { return data_; } }; +template +const uint64_t arg_store::TYPES = IS_PACKED ? + internal::get_types() : + -static_cast(NUM_ARGS); + template inline arg_store make_args(const Args & ... args) { return arg_store(args...); diff --git a/include/fmt/format.h b/include/fmt/format.h index 3846ba70..3fc54d51 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -293,7 +293,7 @@ namespace internal { // Casts nonnegative integer to unsigned. template -constexpr typename std::make_unsigned::type to_unsigned(Int value) { +FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { FMT_ASSERT(value >= 0, "negative value"); return static_cast::type>(value); } @@ -561,7 +561,7 @@ template class null_terminating_iterator; template -constexpr const Char *pointer_from(null_terminating_iterator it); +FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator 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 - 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(null_terminating_iterator it); + friend FMT_CONSTEXPR const Char *pointer_from( + null_terminating_iterator it); private: const Char *ptr_; @@ -643,10 +645,10 @@ class null_terminating_iterator { }; template -constexpr const T *pointer_from(const T *p) { return p; } +FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; } template -constexpr const Char *pointer_from(null_terminating_iterator it) { +FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator 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 -constexpr typename std::enable_if< +FMT_CONSTEXPR typename std::enable_if< std::numeric_limits::is_signed, bool>::type is_negative(T value) { return value < 0; } template -constexpr typename std::enable_if< +FMT_CONSTEXPR typename std::enable_if< !std::numeric_limits::is_signed, bool>::type is_negative(T) { return false; } @@ -988,7 +990,7 @@ struct monostate {}; \endrst */ template -constexpr typename std::result_of::type +FMT_CONSTEXPR typename std::result_of::type visit(Visitor &&vis, basic_arg 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 format_specs; template -constexpr unsigned basic_parse_context::next_arg_id() { +FMT_CONSTEXPR unsigned basic_parse_context::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::next_arg_id() { namespace internal { template -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 -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 -constexpr void handle_char_specs( +FMT_CONSTEXPR void handle_char_specs( const basic_format_specs &specs, Handler &&handler) { if (specs.type() && specs.type() != 'c') { handler.on_int(); @@ -1196,7 +1198,7 @@ constexpr void handle_char_specs( } template -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 -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 -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 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 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(*this)); } - constexpr void on_char() {} + FMT_CONSTEXPR void on_char() {} }; template 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 @@ -1412,7 +1416,7 @@ class arg_formatter_base { struct format_string {}; template -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 -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 class width_checker { public: - explicit constexpr width_checker(ErrorHandler &eh) : handler_(eh) {} + explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {} template - constexpr typename std::enable_if< + FMT_CONSTEXPR typename std::enable_if< is_integer::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 - constexpr typename std::enable_if< + FMT_CONSTEXPR typename std::enable_if< !is_integer::value, unsigned long long>::type operator()(T) { handler_.on_error("width is not integer"); return 0; @@ -1495,10 +1499,10 @@ class width_checker { template class precision_checker { public: - explicit constexpr precision_checker(ErrorHandler &eh) : handler_(eh) {} + explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {} template - constexpr typename std::enable_if< + FMT_CONSTEXPR typename std::enable_if< is_integer::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 - constexpr typename std::enable_if< + FMT_CONSTEXPR typename std::enable_if< !is_integer::value, unsigned long long>::type operator()(T) { handler_.on_error("precision is not integer"); return 0; @@ -1520,30 +1524,30 @@ class precision_checker { template class specs_setter { public: - explicit constexpr specs_setter(basic_format_specs &specs): + explicit FMT_CONSTEXPR specs_setter(basic_format_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; } - 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 &specs_; @@ -1554,55 +1558,55 @@ class specs_setter { template 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