diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index f8e0d2a7ec36..38615ffc044c 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -388,6 +388,7 @@ template ::value)> inline bool isnan(T value) { return std::isnan(value); } + template ::value)> inline bool isfinite(T) { return true; @@ -396,6 +397,8 @@ template ::value)> inline bool isfinite(T value) { return std::isfinite(value); } + +//paul - is this fcn unused? template inline int to_int(T value) { FMT_ASSERT(!isnan(value), "nan to int conversion is UB"); if (std::numeric_limits::is_signed) { @@ -409,6 +412,20 @@ template inline int to_int(T value) { return static_cast(value); } +// Convers value to int and checks that it's in the range [0, upper). +template ::value)> +inline int to_nonnegative_int(T value, int upper) { + FMT_ASSERT(value >= 0 && value <= upper, "invalid value"); + return static_cast(value); +} +template ::value)> +inline int to_nonnegative_int(T value, int upper) { + FMT_ASSERT( + std::isnan(value) || (value >= 0 && value <= static_cast(upper)), + "invalid value"); + return static_cast(value); +} + template ::value)> inline T mod(T x, int y) { return x % y; @@ -560,9 +577,9 @@ struct chrono_formatter { std::tm time() const { auto time = std::tm(); - time.tm_hour = to_int(hour()); - time.tm_min = to_int(minute()); - time.tm_sec = to_int(second()); + time.tm_hour = to_nonnegative_int(hour(), 24); + time.tm_min = to_nonnegative_int(minute(), 60); + time.tm_sec = to_nonnegative_int(second(), 60); return time; } @@ -577,7 +594,8 @@ struct chrono_formatter { write_sign(); if (isnan(value)) return write_nan(); typedef typename int_traits::main_type main_type; - main_type n = to_unsigned(to_int(value)); + main_type n = to_unsigned( + to_nonnegative_int(value, (std::numeric_limits::max)())); int num_digits = internal::count_digits(n); if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); out = format_decimal(out, n, num_digits); @@ -624,7 +642,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour(), 2); auto time = tm(); - time.tm_hour = to_int(hour()); + time.tm_hour = to_nonnegative_int(hour(), 24); format_localized(time, "%OH"); } @@ -635,7 +653,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour12(), 2); auto time = tm(); - time.tm_hour = to_int(hour12()); + time.tm_hour = to_nonnegative_int(hour12(), 12); format_localized(time, "%OI"); } @@ -646,7 +664,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(minute(), 2); auto time = tm(); - time.tm_min = to_int(minute()); + time.tm_min = to_nonnegative_int(minute(), 60); format_localized(time, "%OM"); } @@ -679,7 +697,7 @@ struct chrono_formatter { return; } auto time = tm(); - time.tm_sec = to_int(second()); + time.tm_sec = to_nonnegative_int(second(), 60); format_localized(time, "%OS"); } diff --git a/include/fmt/format.h b/include/fmt/format.h index 2dd51bd8ed1e..36498224454f 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -94,10 +95,6 @@ # endif #endif -#if FMT_SECURE_SCL -# include -#endif - #ifdef __has_builtin # define FMT_HAS_BUILTIN(x) __has_builtin(x) #else @@ -268,32 +265,9 @@ inline Dest bit_cast(const Source& source) { return dest; } -// An implementation of begin and end for pre-C++11 compilers such as gcc 4. -template -FMT_CONSTEXPR auto begin(const C& c) -> decltype(c.begin()) { - return c.begin(); -} -template -FMT_CONSTEXPR T* begin(T (&array)[N]) FMT_NOEXCEPT { - return array; -} -template FMT_CONSTEXPR auto end(const C& c) -> decltype(c.end()) { - return c.end(); -} -template -FMT_CONSTEXPR T* end(T (&array)[N]) FMT_NOEXCEPT { - return array + N; -} - -// An implementation of iterator_t for pre-C++20 compilers such as gcc 4. -template struct iterator_t { - typedef decltype(internal::begin(std::declval())) type; -}; - -// For std::result_of in gcc 4.4. -template struct function { - template struct result { typedef Result type; }; -}; +// An implementation of iterator_t for pre-C++20 systems. +template +using iterator_t = decltype(std::begin(std::declval())); template typename Allocator::value_type* allocate(Allocator& alloc, std::size_t n) { @@ -1545,7 +1519,7 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(const Char*& begin, return value; } -template class custom_formatter : public function { +template class custom_formatter { private: typedef typename Context::char_type char_type; @@ -1572,8 +1546,7 @@ template struct is_integer { }; }; -template -class width_checker : public function { +template class width_checker { public: explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} @@ -1593,8 +1566,7 @@ class width_checker : public function { ErrorHandler& handler_; }; -template -class precision_checker : public function { +template class precision_checker { public: explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} @@ -3351,15 +3323,15 @@ arg_join join(It begin, It end, wstring_view sep) { \endrst */ template -arg_join::type, char> join( +arg_join, char> join( const Range& range, string_view sep) { - return join(internal::begin(range), internal::end(range), sep); + return join(std::begin(range), std::end(range), sep); } template -arg_join::type, wchar_t> join( +arg_join, wchar_t> join( const Range& range, wstring_view sep) { - return join(internal::begin(range), internal::end(range), sep); + return join(std::begin(range), std::end(range), sep); } #endif diff --git a/include/fmt/printf.h b/include/fmt/printf.h index c3a48ed4794e..d52f849c7600 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -38,7 +38,7 @@ template <> struct int_checker { static bool fits_in_int(int) { return true; } }; -class printf_precision_handler : public function { +class printf_precision_handler { public: template ::value)> int operator()(T value) { @@ -55,7 +55,7 @@ class printf_precision_handler : public function { }; // An argument visitor that returns true iff arg is a zero integer. -class is_zero_int : public function { +class is_zero_int { public: template ::value)> bool operator()(T value) { @@ -72,8 +72,7 @@ template struct make_unsigned_or_bool : std::make_unsigned {}; template <> struct make_unsigned_or_bool { typedef bool type; }; -template -class arg_converter : public function { +template class arg_converter { private: typedef typename Context::char_type Char; @@ -129,7 +128,7 @@ void convert_arg(basic_format_arg& arg, Char type) { } // Converts an integer argument to char for printf. -template class char_converter : public function { +template class char_converter { private: basic_format_arg& arg_; @@ -148,8 +147,7 @@ template class char_converter : public function { // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. -template -class printf_width_handler : public function { +template class printf_width_handler { private: typedef basic_format_specs format_specs; diff --git a/test/format b/test/format index 53a7b5df5c14..60dc60e56a49 100644 --- a/test/format +++ b/test/format @@ -489,9 +489,7 @@ namespace detail { template class arg_formatter - : public fmt::internal::function< - typename fmt::internal::arg_formatter_base::iterator>, - public fmt::internal::arg_formatter_base { + : public fmt::internal::arg_formatter_base { private: using char_type = typename Range::value_type; using base = fmt::internal::arg_formatter_base; diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 94bc5eeafbbf..2b0067b0f850 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -143,7 +143,7 @@ TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) { grisu_format(4.2f, buf, -1, false, exp); } -template struct ValueExtractor : fmt::internal::function { +template struct value_extractor { T operator()(T value) { return value; } template FMT_NORETURN T operator()(U) { @@ -157,7 +157,7 @@ TEST(FormatTest, ArgConverter) { fmt::visit_format_arg( fmt::internal::arg_converter(arg, 'd'), arg); - EXPECT_EQ(value, fmt::visit_format_arg(ValueExtractor(), arg)); + EXPECT_EQ(value, fmt::visit_format_arg(value_extractor(), arg)); } TEST(FormatTest, FormatNegativeNaN) { diff --git a/test/format-test.cc b/test/format-test.cc index 0d7153e36da8..6c05854cd289 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1890,9 +1890,7 @@ TEST(FormatTest, FixedEnum) { EXPECT_EQ("0", fmt::format("{}", B)); } typedef fmt::back_insert_range> buffer_range; class mock_arg_formatter - : public fmt::internal::function< - fmt::internal::arg_formatter_base::iterator>, - public fmt::internal::arg_formatter_base { + : public fmt::internal::arg_formatter_base { private: MOCK_METHOD1(call, void(long long value));