diff --git a/doc/api.rst b/doc/api.rst index c1eceaaf5a1e..ab02bffb71f9 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -40,7 +40,7 @@ participate in an overload resolution if the latter is not a string. .. _format: .. doxygenfunction:: format(const S&, const Args&...) -.. doxygenfunction:: vformat(const S&, basic_format_args::type>) +.. doxygenfunction:: vformat(const S&, basic_format_args>) .. _print: @@ -183,7 +183,7 @@ You can also write a formatter for a hierarchy of classes:: Output Iterator Support ----------------------- -.. doxygenfunction:: fmt::format_to(OutputIt, const S &, const Args &...) +.. doxygenfunction:: fmt::format_to(OutputIt, const S&, const Args&...) .. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, const Args&...) .. doxygenstruct:: fmt::format_to_n_result :members: @@ -200,7 +200,7 @@ The following user-defined literals are defined in ``fmt/format.h``. Utilities --------- -.. doxygenclass:: fmt::is_char +.. doxygenstruct:: fmt::is_char .. doxygentypedef:: fmt::char_t @@ -357,7 +357,7 @@ user-defined types that have overloaded ``operator<<``:: std::string s = fmt::format("The date is {}", date(2012, 12, 9)); // s == "The date is 2012-12-9" -.. doxygenfunction:: print(std::basic_ostream>&, const S&, const Args&...) +.. doxygenfunction:: print(std::basic_ostream&, const S&, const Args&...) .. _printf-api: @@ -375,6 +375,6 @@ argument type doesn't match its format specification. .. doxygenfunction:: fprintf(std::FILE *, const S&, const Args&...) -.. doxygenfunction:: fprintf(std::basic_ostream>&, const S&, const Args&...) +.. doxygenfunction:: fprintf(std::basic_ostream&, const S&, const Args&...) .. doxygenfunction:: sprintf(const S&, const Args&...) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index f2c7e8081274..060ce31e0485 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -430,7 +430,7 @@ template struct make_unsigned_or_unchanged { }; template ::value, int>::type = 0> + FMT_ENABLE_IF(std::is_integral::value)> inline std::chrono::duration get_milliseconds( std::chrono::duration d) { // this may overflow and/or the result may not fit in the @@ -466,9 +466,8 @@ inline std::chrono::duration get_milliseconds( #endif } -template < - typename Rep, typename Period, - typename std::enable_if::value, int>::type = 0> +template ::value)> inline std::chrono::duration get_milliseconds( std::chrono::duration d) { return std::chrono::duration( diff --git a/include/fmt/core.h b/include/fmt/core.h index c339d0b028b8..342738c5ca27 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -70,16 +70,6 @@ # define FMT_CONSTEXPR_DECL #endif -#ifndef FMT_USE_CONSTEXPR11 -# define FMT_USE_CONSTEXPR11 \ - (FMT_USE_CONSTEXPR || FMT_GCC_VERSION >= 406 || FMT_MSC_VER >= 1900) -#endif -#if FMT_USE_CONSTEXPR11 -# define FMT_CONSTEXPR11 constexpr -#else -# define FMT_CONSTEXPR11 -#endif - #ifndef FMT_OVERRIDE # if FMT_HAS_FEATURE(cxx_override) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 @@ -205,6 +195,7 @@ template using enable_if_t = typename std::enable_if::type; template using conditional_t = typename std::conditional::type; +template using bool_constant = std::integral_constant; // An enable_if helper to be used in template parameters which results in much // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed @@ -239,119 +230,6 @@ FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { FMT_ASSERT(value >= 0, "negative value"); return static_cast::type>(value); } - -/** A contiguous memory buffer with an optional growing ability. */ -template class buffer { - private: - buffer(const buffer&) = delete; - void operator=(const buffer&) = delete; - - T* ptr_; - std::size_t size_; - std::size_t capacity_; - - protected: - // Don't initialize ptr_ since it is not accessed to save a few cycles. - buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} - - buffer(T* p = nullptr, std::size_t sz = 0, std::size_t cap = 0) FMT_NOEXCEPT - : ptr_(p), - size_(sz), - capacity_(cap) {} - - /** Sets the buffer data and capacity. */ - void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { - ptr_ = buf_data; - capacity_ = buf_capacity; - } - - /** Increases the buffer capacity to hold at least *capacity* elements. */ - virtual void grow(std::size_t capacity) = 0; - - public: - using value_type = T; - using const_reference = const T&; - - virtual ~buffer() {} - - T* begin() FMT_NOEXCEPT { return ptr_; } - T* end() FMT_NOEXCEPT { return ptr_ + size_; } - - /** Returns the size of this buffer. */ - std::size_t size() const FMT_NOEXCEPT { return size_; } - - /** Returns the capacity of this buffer. */ - std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } - - /** Returns a pointer to the buffer data. */ - T* data() FMT_NOEXCEPT { return ptr_; } - - /** Returns a pointer to the buffer data. */ - const T* data() const FMT_NOEXCEPT { return ptr_; } - - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ - void resize(std::size_t new_size) { - reserve(new_size); - size_ = new_size; - } - - /** Clears this buffer. */ - void clear() { size_ = 0; } - - /** Reserves space to store at least *capacity* elements. */ - void reserve(std::size_t new_capacity) { - if (new_capacity > capacity_) grow(new_capacity); - } - - void push_back(const T& value) { - reserve(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template void append(const U* begin, const U* end); - - T& operator[](std::size_t index) { return ptr_[index]; } - const T& operator[](std::size_t index) const { return ptr_[index]; } -}; - -// A container-backed buffer. -template -class container_buffer : public buffer { - private: - Container& container_; - - protected: - void grow(std::size_t capacity) FMT_OVERRIDE { - container_.resize(capacity); - this->set(&container_[0], capacity); - } - - public: - explicit container_buffer(Container& c) - : buffer(c.size()), container_(c) {} -}; - -// Extracts a reference to the container from back_insert_iterator. -template -inline Container& get_container(std::back_insert_iterator it) { - using bi_iterator = std::back_insert_iterator; - struct accessor : bi_iterator { - accessor(bi_iterator iter) : bi_iterator(iter) {} - using bi_iterator::container; - }; - return *accessor(it).container; -} - -struct 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. - FMT_API FMT_NORETURN void on_error(const char* message); -}; } // namespace internal /** @@ -498,11 +376,39 @@ template struct is_compile_string : std::is_base_of {}; template ::value)> -FMT_CONSTEXPR basic_string_view to_string_view( - const S& s) { +constexpr basic_string_view to_string_view(const S& s) { return s; } +namespace internal { +void to_string_view(...); +using fmt::v5::to_string_view; + +// Specifies whether S is a string type convertible to fmt::basic_string_view. +// It should be a constexpr function but MSVC 2017 fails to compile it in +// enable_if and MSVC 2015 fails to compile it as an alias template. +template +struct is_string : std::is_class()))> { +}; + +template struct char_t_impl {}; +template struct char_t_impl::value>> { + using result = decltype(to_string_view(std::declval())); + using type = typename result::char_type; +}; + +struct 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. + FMT_API FMT_NORETURN void on_error(const char* message); +}; +} // namespace internal + +/** String's character type. */ +template using char_t = typename internal::char_t_impl::type; + // Parsing context consisting of a format string range being parsed and an // argument counter for automatic indexing. template @@ -534,7 +440,11 @@ class basic_parse_context : private ErrorHandler { } // Returns the next argument index. - FMT_CONSTEXPR unsigned next_arg_id(); + FMT_CONSTEXPR unsigned 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"); + return 0; + } FMT_CONSTEXPR bool check_arg_id(unsigned) { if (next_arg_id_ > 0) { @@ -566,49 +476,139 @@ template class basic_format_args; // A formatter for objects of type T. template struct formatter { + // A deleted default constructor indicates a disabled formatter. formatter() = delete; }; template -struct convert_to_int - : std::integral_constant::value && - std::is_convertible::value> {}; +struct FMT_DEPRECATED convert_to_int + : bool_constant::value && + std::is_convertible::value> {}; namespace internal { -template struct no_formatter_error : std::false_type {}; +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. +template +using has_formatter = + std::is_constructible>; -template -struct fallback_formatter { - static_assert( - no_formatter_error::value, - "don't know how to format the type, include fmt/ostream.h if it provides " - "an operator<< that should be used"); +/** A contiguous memory buffer with an optional growing ability. */ +template class buffer { + private: + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + T* ptr_; + std::size_t size_; + std::size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} + + buffer(T* p = nullptr, std::size_t sz = 0, std::size_t cap = 0) FMT_NOEXCEPT + : ptr_(p), + size_(sz), + capacity_(cap) {} + + /** Sets the buffer data and capacity. */ + void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual void grow(std::size_t capacity) = 0; + + public: + using value_type = T; + using const_reference = const T&; + + virtual ~buffer() {} + + T* begin() FMT_NOEXCEPT { return ptr_; } + T* end() FMT_NOEXCEPT { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + std::size_t size() const FMT_NOEXCEPT { return size_; } + + /** Returns the capacity of this buffer. */ + std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } + + /** Returns a pointer to the buffer data. */ + T* data() FMT_NOEXCEPT { return ptr_; } + + /** Returns a pointer to the buffer data. */ + const T* data() const FMT_NOEXCEPT { return ptr_; } + + /** + Resizes the buffer. If T is a POD type new elements may not be initialized. + */ + void resize(std::size_t new_size) { + reserve(new_size); + size_ = new_size; + } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + /** Reserves space to store at least *capacity* elements. */ + void reserve(std::size_t new_capacity) { + if (new_capacity > capacity_) grow(new_capacity); + } + + void push_back(const T& value) { + reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template void append(const U* begin, const U* end); + + T& operator[](std::size_t index) { return ptr_[index]; } + const T& operator[](std::size_t index) const { return ptr_[index]; } }; -struct dummy_string_view { - typedef void char_type; +// A container-backed buffer. +template +class container_buffer : public buffer { + private: + Container& container_; + + protected: + void grow(std::size_t capacity) FMT_OVERRIDE { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit container_buffer(Container& c) + : buffer(c.size()), container_(c) {} }; -dummy_string_view to_string_view(...); -using fmt::v5::to_string_view; -// Specifies whether S is a string type convertible to fmt::basic_string_view. -// It should be a constexpr function but MSVC 2017 fails to compile it in -// enable_if. -template -struct is_string - : std::integral_constant< - bool, - !std::is_same()))>::value> {}; - -template struct char_t_impl { - typedef decltype(to_string_view(std::declval())) result; - typedef typename result::char_type type; +// Extracts a reference to the container from back_insert_iterator. +template +inline Container& get_container(std::back_insert_iterator it) { + using bi_iterator = std::back_insert_iterator; + struct accessor : bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; +} + +template +struct fallback_formatter { + fallback_formatter() = delete; }; -template struct named_arg_base; +// Specifies if T has an enabled fallback_formatter specialization. +template +using has_fallback_formatter = + std::is_constructible>; +template struct named_arg_base; template struct named_arg; enum type { @@ -632,6 +632,26 @@ enum type { custom_type }; +// Maps core type T to the corresponding type enum constant. +template +struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant : std::integral_constant {} + +FMT_TYPE_CONSTANT(int, int_type); +FMT_TYPE_CONSTANT(unsigned, uint_type); +FMT_TYPE_CONSTANT(long long, long_long_type); +FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +FMT_TYPE_CONSTANT(bool, bool_type); +FMT_TYPE_CONSTANT(Char, char_type); +FMT_TYPE_CONSTANT(double, double_type); +FMT_TYPE_CONSTANT(long double, long_double_type); +FMT_TYPE_CONSTANT(const Char*, cstring_type); +FMT_TYPE_CONSTANT(basic_string_view, string_type); +FMT_TYPE_CONSTANT(const void*, pointer_type); + FMT_CONSTEXPR bool is_integral(type t) { FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); return t > internal::none_type && t <= internal::last_integer_type; @@ -653,10 +673,6 @@ template struct custom_value { void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); }; -template -using is_formattable = - std::is_constructible>; - // A formatting argument value. template class value { public: @@ -671,33 +687,32 @@ template class value { long double long_double_value; const void* pointer; string_value string; - string_value sstring; - string_value ustring; custom_value custom; + const named_arg_base* named_arg; }; FMT_CONSTEXPR value(int val = 0) : int_value(val) {} FMT_CONSTEXPR 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(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; + string.value = reinterpret_cast(val); } value(const unsigned char* val) { static_assert(std::is_same::value, "incompatible string types"); - ustring.value = val; + string.value = reinterpret_cast(val); } value(basic_string_view val) { string.value = val.data(); string.size = val.size(); } - value(const void* val) { pointer = val; } + value(const void* val) : pointer(val) {} template explicit value(const T& val) { custom.value = &val; @@ -705,14 +720,12 @@ template class value { // have different extension points, e.g. `formatter` for `format` and // `printf_formatter` for `printf`. custom.format = &format_custom_arg< - T, conditional_t::value, + T, conditional_t::value, typename Context::template formatter_type, internal::fallback_formatter>>; } - const named_arg_base& as_named_arg() { - return *static_cast*>(pointer); - } + value(const named_arg_base& val) { named_arg = &val; } private: // Formats an argument of a custom type, such as a user-defined class. @@ -771,6 +784,7 @@ FMT_MAKE_VALUE_SAME(long_long_type, long long) FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long) FMT_MAKE_VALUE(int_type, signed char, int) FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) +FMT_MAKE_VALUE(char_type, char, int) // This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4. template make_value(Char val) { return {val}; } -template ::value)> -FMT_CONSTEXPR init make_value(char val) { - return val; +template ::value && !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR init make_value(const T&) { + static_assert(!sizeof(T), "mixing character types is disallowed"); } FMT_MAKE_VALUE(double_type, float, double) @@ -795,17 +810,27 @@ FMT_MAKE_VALUE(cstring_type, typename C::char_type*, const typename C::char_type*) FMT_MAKE_VALUE(cstring_type, const typename C::char_type*, const typename C::char_type*) - FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*) FMT_MAKE_VALUE_SAME(cstring_type, const signed char*) FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*) FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*) -FMT_MAKE_VALUE_SAME(string_type, basic_string_view) -FMT_MAKE_VALUE(string_type, - typename basic_string_view::type, - basic_string_view) -FMT_MAKE_VALUE(string_type, const std::basic_string&, - basic_string_view) + +template ::value)> +constexpr init, string_type> +make_value(const S& val) { + static_assert(std::is_same>::value, + "mismatch between char-types of context and argument"); + return to_string_view(val); +} + +template < + typename C, typename T, typename Char = typename C::char_type, + FMT_ENABLE_IF(std::is_constructible, T>::value && + !internal::is_string::value)> +inline init, string_type> make_value(const T& val) { + return basic_string_view(val); +} + FMT_MAKE_VALUE(pointer_type, void*, const void*) FMT_MAKE_VALUE_SAME(pointer_type, const void*) FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) @@ -821,27 +846,20 @@ void make_value(const T*) { } template ::value&& - std::is_enum::value)> + FMT_ENABLE_IF(std::is_enum::value && !has_formatter::value && + !has_fallback_formatter::value)> inline init make_value(const T& val) { return static_cast(val); } -template < - typename C, typename T, typename Char = typename C::char_type, - FMT_ENABLE_IF(std::is_constructible, T>::value && - !internal::is_string::value)> -inline init, string_type> make_value(const T& val) { - return basic_string_view(val); -} - -// Implicit conversion to std::string is not handled here because it's -// unsafe: https://github.com/fmtlib/fmt/issues/729 +// Implicit conversion to std::string is disallowed because it would be unsafe: +// https://github.com/fmtlib/fmt/issues/729 template < typename C, typename T, typename Char = typename C::char_type, typename U = typename std::remove_volatile::type, - FMT_ENABLE_IF(!convert_to_int::value && - !std::is_same::value && + FMT_ENABLE_IF(!std::is_same::value && + (!std::is_convertible::value || + has_fallback_formatter::value) && !std::is_convertible>::value && !std::is_constructible, U>::value && !internal::is_string::value)> @@ -849,22 +867,20 @@ inline init make_value(const T& val) { return val; } -template -init make_value( - const named_arg& val) { - basic_format_arg arg = make_arg(val.value); - std::memcpy(val.data, &arg, sizeof(arg)); - return static_cast(&val); +template ::value&& std::is_convertible< + T, int>::value&& has_formatter::value && + !std::is_same::value)> +inline init make_value(const T& val) { + return val; } -template ::value)> -FMT_CONSTEXPR11 init, string_type> -make_value(const S& val) { - // Handle adapted strings. - static_assert(std::is_same::type>::value, - "mismatch between char-types of context and argument"); - return to_string_view(val); +template +init&, named_arg_type> make_value( + const named_arg& val) { + basic_format_arg arg = make_arg(val.value); + std::memcpy(val.data, &arg, sizeof(arg)); + return val; } // Maximum number of arguments with packed types. @@ -991,7 +1007,7 @@ template class arg_map { unsigned size_; void push_back(value val) { - const internal::named_arg_base& named = val.as_named_arg(); + const auto& named = *val.named_arg; map_[size_] = entry{named.name, named.template deserialize()}; ++size_; } @@ -1029,12 +1045,12 @@ template struct get_type { static const type value = value_type::type_tag; }; -template FMT_CONSTEXPR11 unsigned long long get_types() { +template constexpr unsigned long long get_types() { return 0; } template -FMT_CONSTEXPR11 unsigned long long get_types() { +constexpr unsigned long long get_types() { return get_type::value | (get_types() << 4); } @@ -1123,53 +1139,26 @@ using wformat_context = buffer_context; */ template class format_arg_store { private: - static const size_t NUM_ARGS = sizeof...(Args); - - // Packed is a macro on MinGW so use IS_PACKED instead. - static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; + static const size_t num_args = sizeof...(Args); + static const bool is_packed = num_args < internal::max_packed_args; - using value_type = conditional_t, + using value_type = conditional_t, basic_format_arg>; // If the arguments are not packed, add one more element to mark the end. - static const size_t DATA_SIZE = - NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1); - value_type data_[DATA_SIZE]; + value_type data_[num_args + (!is_packed || num_args == 0 ? 1 : 0)]; friend class basic_format_args; - static FMT_CONSTEXPR11 unsigned long long get_types() { - return IS_PACKED ? internal::get_types() - : internal::is_unpacked_bit | NUM_ARGS; - } - public: -#if FMT_USE_CONSTEXPR11 - static FMT_CONSTEXPR11 unsigned long long TYPES = get_types(); -#else - static const unsigned long long TYPES; -#endif + static constexpr unsigned long long TYPES = + is_packed ? internal::get_types() + : internal::is_unpacked_bit | num_args; -#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \ - (FMT_MSC_VER && FMT_MSC_VER <= 1800) - // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. - format_arg_store(const Args&... args) { - value_type init[DATA_SIZE] = { - internal::make_arg(args)...}; - std::memcpy(data_, init, sizeof(init)); - } -#else format_arg_store(const Args&... args) - : data_{internal::make_arg(args)...} {} -#endif + : data_{internal::make_arg(args)...} {} }; -#if !FMT_USE_CONSTEXPR11 -template -const unsigned long long format_arg_store::TYPES = - get_types(); -#endif - /** \rst Constructs an `~fmt::format_arg_store` object that contains references to @@ -1260,7 +1249,7 @@ template class basic_format_args { format_arg get(size_type index) const { format_arg arg = do_get(index); if (arg.type_ == internal::named_arg_type) - arg = arg.value_.as_named_arg().template deserialize(); + arg = arg.value_.named_arg->template deserialize(); return arg; } @@ -1284,9 +1273,6 @@ struct wformat_args : basic_format_args { : basic_format_args(std::forward(arg)...) {} }; -/** String's character type. */ -template using char_t = typename internal::char_t_impl::type; - namespace internal { template FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, unsigned id) { @@ -1317,15 +1303,12 @@ template struct named_arg : named_arg_base { : named_arg_base(name), value(val) {} }; -template ::value)> +template ::value)> inline void check_format_string(const S&) {} -template ::value)> +template ::value)> void check_format_string(S); -template ::value, char_t>> +template > inline format_arg_store, Args...> make_args_checked( const S& format_str, const Args&... args) { internal::check_format_string(format_str); @@ -1406,8 +1389,7 @@ inline std::back_insert_iterator format_to( {internal::make_args_checked(format_str, args...)}); } -template ::value, char_t>> +template > inline std::basic_string vformat( const S& format_str, basic_format_args> args) { return internal::vformat(to_string_view(format_str), args); @@ -1425,8 +1407,7 @@ inline std::basic_string vformat( */ // Pass char_t as a default template parameter instead of using // std::basic_string> to reduce the symbol size. -template ::value, char_t>> +template > inline std::basic_string format(const S& format_str, const Args&... args) { return internal::vformat(to_string_view(format_str), diff --git a/include/fmt/format.h b/include/fmt/format.h index b60bb95f0299..e4327b6a0e5a 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -785,10 +785,10 @@ inline char8_t to_char8_t(char c) { return static_cast(c); } template struct needs_conversion - : std::integral_constant< - bool, std::is_same::value_type, - char>::value && - std::is_same::value> {}; + : bool_constant< + std::is_same::value_type, + char>::value && + std::is_same::value> {}; template ::value)> @@ -1117,13 +1117,6 @@ struct basic_format_specs : align_spec, core_format_specs { typedef basic_format_specs format_specs; -template -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"); - return 0; -} - namespace internal { namespace grisu_options { @@ -1817,11 +1810,9 @@ struct string_view_metadata { : offset_(view.data() - primary_string.data()), size_(view.size()) {} FMT_CONSTEXPR string_view_metadata(std::size_t offset, std::size_t size) : offset_(offset), size_(size) {} - template ::value, char_t>> - FMT_CONSTEXPR basic_string_view to_view(S&& str) const { - const auto view = to_string_view(str); - return basic_string_view(view.data() + offset_, size_); + template + FMT_CONSTEXPR basic_string_view to_view(const Char* str) const { + return {str + offset_, size_}; } std::size_t offset_; @@ -2192,7 +2183,7 @@ FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( ParseContext& ctx) { // GCC 7.2 requires initializer. typedef typename ParseContext::char_type char_type; - conditional_t::value, + conditional_t>::value, formatter, internal::fallback_formatter> f; @@ -2268,14 +2259,6 @@ void check_format_string(S format_str) { (void)invalid_format; } -// 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 -struct format_type - : std::integral_constant::value != custom_type> { -}; - template