@ -18,7 +18,7 @@
# include <ostream>
# include <type_traits>
# include " format.h"
# include " ostream.h" // formatbuf
FMT_BEGIN_NAMESPACE
@ -72,7 +72,8 @@ template <typename To, typename From,
FMT_ENABLE_IF ( ! std : : is_same < From , To > : : value & &
std : : numeric_limits < From > : : is_signed = =
std : : numeric_limits < To > : : is_signed ) >
FMT_CONSTEXPR To lossless_integral_conversion ( const From from , int & ec ) {
FMT_CONSTEXPR auto lossless_integral_conversion ( const From from , int & ec )
- > To {
ec = 0 ;
using F = std : : numeric_limits < From > ;
using T = std : : numeric_limits < To > ;
@ -101,7 +102,8 @@ template <typename To, typename From,
FMT_ENABLE_IF ( ! std : : is_same < From , To > : : value & &
std : : numeric_limits < From > : : is_signed ! =
std : : numeric_limits < To > : : is_signed ) >
FMT_CONSTEXPR To lossless_integral_conversion ( const From from , int & ec ) {
FMT_CONSTEXPR auto lossless_integral_conversion ( const From from , int & ec )
- > To {
ec = 0 ;
using F = std : : numeric_limits < From > ;
using T = std : : numeric_limits < To > ;
@ -133,7 +135,8 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
template < typename To , typename From ,
FMT_ENABLE_IF ( std : : is_same < From , To > : : value ) >
FMT_CONSTEXPR To lossless_integral_conversion ( const From from , int & ec ) {
FMT_CONSTEXPR auto lossless_integral_conversion ( const From from , int & ec )
- > To {
ec = 0 ;
return from ;
} // function
@ -154,7 +157,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// clang-format on
template < typename To , typename From ,
FMT_ENABLE_IF ( ! std : : is_same < From , To > : : value ) >
FMT_CONSTEXPR T o safe_float_conversion ( const From from , int & ec ) {
FMT_CONSTEXPR aut o safe_float_conversion ( const From from , int & ec ) - > To {
ec = 0 ;
using T = std : : numeric_limits < To > ;
static_assert ( std : : is_floating_point < From > : : value , " From must be floating " ) ;
@ -176,7 +179,7 @@ FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
template < typename To , typename From ,
FMT_ENABLE_IF ( std : : is_same < From , To > : : value ) >
FMT_CONSTEXPR T o safe_float_conversion ( const From from , int & ec ) {
FMT_CONSTEXPR aut o safe_float_conversion ( const From from , int & ec ) - > To {
ec = 0 ;
static_assert ( std : : is_floating_point < From > : : value , " From must be floating " ) ;
return from ;
@ -188,8 +191,8 @@ FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
template < typename To , typename FromRep , typename FromPeriod ,
FMT_ENABLE_IF ( std : : is_integral < FromRep > : : value ) ,
FMT_ENABLE_IF ( std : : is_integral < typename To : : rep > : : value ) >
T o safe_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ,
int & ec ) {
aut o safe_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ,
int & ec ) - > To {
using From = std : : chrono : : duration < FromRep , FromPeriod > ;
ec = 0 ;
// the basic idea is that we need to convert from count() in the from type
@ -240,8 +243,8 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
template < typename To , typename FromRep , typename FromPeriod ,
FMT_ENABLE_IF ( std : : is_floating_point < FromRep > : : value ) ,
FMT_ENABLE_IF ( std : : is_floating_point < typename To : : rep > : : value ) >
T o safe_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ,
int & ec ) {
aut o safe_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ,
int & ec ) - > To {
using From = std : : chrono : : duration < FromRep , FromPeriod > ;
ec = 0 ;
if ( std : : isnan ( from . count ( ) ) ) {
@ -321,12 +324,12 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
namespace detail {
template < typename T = void > struct null { } ;
inline null < > localtime_r FMT_NOMACRO ( . . . ) { return null < > ( ) ; }
inline null < > localtime_s ( . . . ) { return null < > ( ) ; }
inline null < > gmtime_r ( . . . ) { return null < > ( ) ; }
inline null < > gmtime_s ( . . . ) { return null < > ( ) ; }
inline auto localtime_r FMT_NOMACRO ( . . . ) - > null < > { return null < > ( ) ; }
inline auto localtime_s ( . . . ) - > null < > { return null < > ( ) ; }
inline auto gmtime_r ( . . . ) - > null < > { return null < > ( ) ; }
inline auto gmtime_s ( . . . ) - > null < > { return null < > ( ) ; }
inline const std : : locale & get_classic_locale ( ) {
inline auto get_classic_locale ( ) - > const std : : locale & {
static const auto & locale = std : : locale : : classic ( ) ;
return locale ;
}
@ -336,8 +339,6 @@ template <typename CodeUnit> struct codecvt_result {
CodeUnit buf [ max_size ] ;
CodeUnit * end ;
} ;
template < typename CodeUnit >
constexpr const size_t codecvt_result < CodeUnit > : : max_size ;
template < typename CodeUnit >
void write_codecvt ( codecvt_result < CodeUnit > & out , string_view in_buf ,
@ -377,8 +378,8 @@ auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
unit_t unit ;
write_codecvt ( unit , in , loc ) ;
// In UTF-8 is used one to four one-byte code units.
unicode_to_utf8 < code_unit , basic_memory_buffer < char , unit_t : : max_size * 4 > >
u;
auto u =
to_ utf8< code_unit , basic_memory_buffer < char , unit_t : : max_size * 4 > > ( ) ;
if ( ! u . convert ( { unit . buf , to_unsigned ( unit . end - unit . buf ) } ) )
FMT_THROW ( format_error ( " failed to format time " ) ) ;
return copy_str < char > ( u . c_str ( ) , u . c_str ( ) + u . size ( ) , out ) ;
@ -408,8 +409,7 @@ inline void do_write(buffer<Char>& buf, const std::tm& time,
auto & & format_buf = formatbuf < std : : basic_streambuf < Char > > ( buf ) ;
auto & & os = std : : basic_ostream < Char > ( & format_buf ) ;
os . imbue ( loc ) ;
using iterator = std : : ostreambuf_iterator < Char > ;
const auto & facet = std : : use_facet < std : : time_put < Char , iterator > > ( loc ) ;
const auto & facet = std : : use_facet < std : : time_put < Char > > ( loc ) ;
auto end = facet . put ( os , os , Char ( ' ' ) , & time , format , modifier ) ;
if ( end . failed ( ) ) FMT_THROW ( format_error ( " failed to format time " ) ) ;
}
@ -432,6 +432,51 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc,
return write_encoded_tm_str ( out , string_view ( buf . data ( ) , buf . size ( ) ) , loc ) ;
}
template < typename Rep1 , typename Rep2 >
struct is_same_arithmetic_type
: public std : : integral_constant < bool ,
( std : : is_integral < Rep1 > : : value & &
std : : is_integral < Rep2 > : : value ) | |
( std : : is_floating_point < Rep1 > : : value & &
std : : is_floating_point < Rep2 > : : value ) > {
} ;
template <
typename To , typename FromRep , typename FromPeriod ,
FMT_ENABLE_IF ( is_same_arithmetic_type < FromRep , typename To : : rep > : : value ) >
auto fmt_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ) - > To {
# if FMT_SAFE_DURATION_CAST
// Throwing version of safe_duration_cast is only available for
// integer to integer or float to float casts.
int ec ;
To to = safe_duration_cast : : safe_duration_cast < To > ( from , ec ) ;
if ( ec ) FMT_THROW ( format_error ( " cannot format duration " ) ) ;
return to ;
# else
// Standard duration cast, may overflow.
return std : : chrono : : duration_cast < To > ( from ) ;
# endif
}
template <
typename To , typename FromRep , typename FromPeriod ,
FMT_ENABLE_IF ( ! is_same_arithmetic_type < FromRep , typename To : : rep > : : value ) >
auto fmt_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ) - > To {
// Mixed integer <-> float cast is not supported by safe_duration_cast.
return std : : chrono : : duration_cast < To > ( from ) ;
}
template < typename Duration >
auto to_time_t (
std : : chrono : : time_point < std : : chrono : : system_clock , Duration > time_point )
- > std : : time_t {
// Cannot use std::chrono::system_clock::to_time_t since this would first
// require a cast to std::chrono::system_clock::time_point, which could
// overflow.
return fmt_duration_cast < std : : chrono : : duration < std : : time_t > > (
time_point . time_since_epoch ( ) )
. count ( ) ;
}
} // namespace detail
FMT_BEGIN_EXPORT
@ -441,29 +486,29 @@ FMT_BEGIN_EXPORT
expressed in local time . Unlike ` ` std : : localtime ` ` , this function is
thread - safe on most platforms .
*/
inline std : : tm localtime ( std : : time_t time ) {
inline auto localtime ( std : : time_t time ) - > std : : tm {
struct dispatcher {
std : : time_t time_ ;
std : : tm tm_ ;
dispatcher ( std : : time_t t ) : time_ ( t ) { }
bool run ( ) {
auto run ( ) - > bool {
using namespace fmt : : detail ;
return handle ( localtime_r ( & time_ , & tm_ ) ) ;
}
bool handle ( std : : tm * tm ) { return tm ! = nullptr ; }
auto handle ( std : : tm * tm ) - > bool { return tm ! = nullptr ; }
bool handle ( detail : : null < > ) {
auto handle ( detail : : null < > ) - > bool {
using namespace fmt : : detail ;
return fallback ( localtime_s ( & tm_ , & time_ ) ) ;
}
bool fallback ( int res ) { return res = = 0 ; }
auto fallback ( int res ) - > bool { return res = = 0 ; }
# if !FMT_MSC_VERSION
bool fallback ( detail : : null < > ) {
auto fallback ( detail : : null < > ) - > bool {
using namespace fmt : : detail ;
std : : tm * tm = std : : localtime ( & time_ ) ;
if ( tm ) tm_ = * tm ;
@ -480,8 +525,8 @@ inline std::tm localtime(std::time_t time) {
# if FMT_USE_LOCAL_TIME
template < typename Duration >
inline auto localtime ( std : : chrono : : local_time < Duration > time ) - > std : : tm {
return localtime ( std : : chrono : : system_clock : : to_time_t (
std: : chrono : : current_zone ( ) - > to_sys ( time ) ) ) ;
return localtime (
detail: : to_time_t ( std: : chrono : : current_zone ( ) - > to_sys ( time ) ) ) ;
}
# endif
@ -490,90 +535,49 @@ inline auto localtime(std::chrono::local_time<Duration> time) -> std::tm {
expressed in Coordinated Universal Time ( UTC ) . Unlike ` ` std : : gmtime ` ` , this
function is thread - safe on most platforms .
*/
inline std : : tm gmtime ( std : : time_t time ) {
inline auto gmtime ( std : : time_t time ) - > std : : tm {
struct dispatcher {
std : : time_t time_ ;
std : : tm tm_ ;
dispatcher ( std : : time_t t ) : time_ ( t ) { }
bool run ( ) {
auto run ( ) - > bool {
using namespace fmt : : detail ;
return handle ( gmtime_r ( & time_ , & tm_ ) ) ;
}
bool handle ( std : : tm * tm ) { return tm ! = nullptr ; }
auto handle ( std : : tm * tm ) - > bool { return tm ! = nullptr ; }
bool handle ( detail : : null < > ) {
auto handle ( detail : : null < > ) - > bool {
using namespace fmt : : detail ;
return fallback ( gmtime_s ( & tm_ , & time_ ) ) ;
}
bool fallback ( int res ) { return res = = 0 ; }
auto fallback ( int res ) - > bool { return res = = 0 ; }
# if !FMT_MSC_VERSION
bool fallback ( detail : : null < > ) {
auto fallback ( detail : : null < > ) - > bool {
std : : tm * tm = std : : gmtime ( & time_ ) ;
if ( tm ) tm_ = * tm ;
return tm ! = nullptr ;
}
# endif
} ;
dispatcher gt ( time ) ;
auto gt = dispatcher( time ) ;
// Too big time values may be unsupported.
if ( ! gt . run ( ) ) FMT_THROW ( format_error ( " time_t value out of range " ) ) ;
return gt . tm_ ;
}
inline std : : tm gmtime (
std : : chrono : : time_point < std : : chrono : : system_clock > time_point ) {
return gmtime ( std : : chrono : : system_clock : : to_time_t ( time_point ) ) ;
template < typename Duration >
inline auto gmtime (
std : : chrono : : time_point < std : : chrono : : system_clock , Duration > time_point )
- > std : : tm {
return gmtime ( detail : : to_time_t ( time_point ) ) ;
}
FMT_BEGIN_DETAIL_NAMESPACE
// DEPRECATED!
template < typename Char >
FMT_CONSTEXPR auto parse_align ( const Char * begin , const Char * end ,
format_specs < Char > & specs ) - > const Char * {
FMT_ASSERT ( begin ! = end , " " ) ;
auto align = align : : none ;
auto p = begin + code_point_length ( begin ) ;
if ( end - p < = 0 ) p = begin ;
for ( ; ; ) {
switch ( to_ascii ( * p ) ) {
case ' < ' :
align = align : : left ;
break ;
case ' > ' :
align = align : : right ;
break ;
case ' ^ ' :
align = align : : center ;
break ;
}
if ( align ! = align : : none ) {
if ( p ! = begin ) {
auto c = * begin ;
if ( c = = ' } ' ) return begin ;
if ( c = = ' { ' ) {
throw_format_error ( " invalid fill character '{' " ) ;
return begin ;
}
specs . fill = { begin , to_unsigned ( p - begin ) } ;
begin = p + 1 ;
} else {
+ + begin ;
}
break ;
} else if ( p = = begin ) {
break ;
}
p = begin ;
}
specs . align = align ;
return begin ;
}
namespace detail {
// Writes two-digit numbers a, b and c separated by sep to buf.
// The method by Pavel Novikov based on
@ -609,7 +613,8 @@ inline void write_digit2_separated(char* buf, unsigned a, unsigned b,
}
}
template < typename Period > FMT_CONSTEXPR inline const char * get_units ( ) {
template < typename Period >
FMT_CONSTEXPR inline auto get_units ( ) - > const char * {
if ( std : : is_same < Period , std : : atto > : : value ) return " as " ;
if ( std : : is_same < Period , std : : femto > : : value ) return " fs " ;
if ( std : : is_same < Period , std : : pico > : : value ) return " ps " ;
@ -627,8 +632,9 @@ template <typename Period> FMT_CONSTEXPR inline const char* get_units() {
if ( std : : is_same < Period , std : : tera > : : value ) return " Ts " ;
if ( std : : is_same < Period , std : : peta > : : value ) return " Ps " ;
if ( std : : is_same < Period , std : : exa > : : value ) return " Es " ;
if ( std : : is_same < Period , std : : ratio < 60 > > : : value ) return " m " ;
if ( std : : is_same < Period , std : : ratio < 60 > > : : value ) return " m in " ;
if ( std : : is_same < Period , std : : ratio < 3600 > > : : value ) return " h " ;
if ( std : : is_same < Period , std : : ratio < 86400 > > : : value ) return " d " ;
return nullptr ;
}
@ -664,9 +670,8 @@ auto write_padding(OutputIt out, pad_type pad) -> OutputIt {
// Parses a put_time-like format string and invokes handler actions.
template < typename Char , typename Handler >
FMT_CONSTEXPR const Char * parse_chrono_format ( const Char * begin ,
const Char * end ,
Handler & & handler ) {
FMT_CONSTEXPR auto parse_chrono_format ( const Char * begin , const Char * end ,
Handler & & handler ) - > const Char * {
if ( begin = = end | | * begin = = ' } ' ) return begin ;
if ( * begin ! = ' % ' ) FMT_THROW ( format_error ( " invalid format " ) ) ;
auto ptr = begin ;
@ -997,25 +1002,25 @@ struct tm_format_checker : null_chrono_spec_handler<tm_format_checker> {
FMT_CONSTEXPR void on_tz_name ( ) { }
} ;
inline const char * tm_wday_full_name ( int wday ) {
inline auto tm_wday_full_name ( int wday ) - > const char * {
static constexpr const char * full_name_list [ ] = {
" Sunday " , " Monday " , " Tuesday " , " Wednesday " ,
" Thursday " , " Friday " , " Saturday " } ;
return wday > = 0 & & wday < = 6 ? full_name_list [ wday ] : " ? " ;
}
inline const char * tm_wday_short_name ( int wday ) {
inline auto tm_wday_short_name ( int wday ) - > const char * {
static constexpr const char * short_name_list [ ] = { " Sun " , " Mon " , " Tue " , " Wed " ,
" Thu " , " Fri " , " Sat " } ;
return wday > = 0 & & wday < = 6 ? short_name_list [ wday ] : " ??? " ;
}
inline const char * tm_mon_full_name ( int mon ) {
inline auto tm_mon_full_name ( int mon ) - > const char * {
static constexpr const char * full_name_list [ ] = {
" January " , " February " , " March " , " April " , " May " , " June " ,
" July " , " August " , " September " , " October " , " November " , " December " } ;
return mon > = 0 & & mon < = 11 ? full_name_list [ mon ] : " ? " ;
}
inline const char * tm_mon_short_name ( int mon ) {
inline auto tm_mon_short_name ( int mon ) - > const char * {
static constexpr const char * short_name_list [ ] = {
" Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " ,
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " ,
@ -1047,21 +1052,21 @@ inline void tzset_once() {
// Converts value to Int and checks that it's in the range [0, upper).
template < typename T , typename Int , FMT_ENABLE_IF ( std : : is_integral < T > : : value ) >
inline Int to_nonnegative_int ( T value , Int upper ) {
FMT_ASSERT ( std : : is_unsigned < Int > : : value ||
( value > = 0 & & to_unsigned ( value ) < = to_unsigned ( upper ) ) ,
" invalid value " ) ;
(void ) upper ;
inline auto to_nonnegative_int ( T value , Int upper ) - > Int {
if ( ! std : : is_unsigned < Int > : : value &&
( value < 0 | | to_unsigned ( value ) > to_unsigned ( upper ) ) ) {
FMT_THROW ( fmt : : format_error ( " chrono value is out of range " ) ) ;
}
return static_cast < Int > ( value ) ;
}
template < typename T , typename Int , FMT_ENABLE_IF ( ! std : : is_integral < T > : : value ) >
inline Int to_nonnegative_int ( T value , Int upper ) {
inline auto to_nonnegative_int ( T value , Int upper ) - > Int {
if ( value < 0 | | value > static_cast < T > ( upper ) )
FMT_THROW ( format_error ( " invalid value " ) ) ;
return static_cast < Int > ( value ) ;
}
constexpr long long pow10 ( std : : uint32_t n ) {
constexpr auto pow10 ( std : : uint32_t n ) - > long long {
return n = = 0 ? 1 : 10 * pow10 ( n - 1 ) ;
}
@ -1095,13 +1100,12 @@ void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) {
std : : chrono : : seconds : : rep > : : type ,
std : : ratio < 1 , detail : : pow10 ( num_fractional_digits ) > > ;
const auto fractional =
d - std : : chrono : : duration_cast < std : : chrono : : seconds > ( d ) ;
const auto fractional = d - fmt_duration_cast < std : : chrono : : seconds > ( d ) ;
const auto subseconds =
std : : chrono : : treat_as_floating_point <
typename subsecond_precision : : rep > : : value
? fractional . count ( )
: std: : chrono : : duration_cast< subsecond_precision > ( fractional ) . count ( ) ;
: fmt_ duration_cast< subsecond_precision > ( fractional ) . count ( ) ;
auto n = static_cast < uint32_or_64_or_128_t < long long > > ( subseconds ) ;
const int num_digits = detail : : count_digits ( n ) ;
@ -1152,11 +1156,11 @@ void write_floating_seconds(memory_buffer& buf, Duration duration,
num_fractional_digits = 6 ;
}
format_to ( std : : back_inserter ( buf ) , FMT_STRING ( " {:.{}f} " ) ,
std : : fmod ( val * static_cast < rep > ( Duration : : period : : num ) /
static_cast < rep > ( Duration : : period : : den ) ,
static_cast < rep > ( 60 ) ) ,
num_fractional_digits ) ;
fmt : : format_to ( std : : back_inserter ( buf ) , FMT_STRING ( " {:.{}f} " ) ,
std : : fmod ( val * static_cast < rep > ( Duration : : period : : num ) /
static_cast < rep > ( Duration : : period : : den ) ,
static_cast < rep > ( 60 ) ) ,
num_fractional_digits ) ;
}
template < typename OutputIt , typename Char ,
@ -1217,8 +1221,7 @@ class tm_writer {
return static_cast < int > ( l ) ;
}
// Algorithm:
// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date
// Algorithm: https://en.wikipedia.org/wiki/ISO_week_date.
auto iso_year_weeks ( long long curr_year ) const noexcept - > int {
const auto prev_year = curr_year - 1 ;
const auto curr_p =
@ -1358,7 +1361,7 @@ class tm_writer {
subsecs_ ( subsecs ) ,
tm_ ( tm ) { }
OutputIt out ( ) cons t { return out_ ; }
auto out ( ) const - > OutputI t { return out_ ; }
FMT_CONSTEXPR void on_text ( const Char * begin , const Char * end ) {
out_ = copy_str < Char > ( begin , end , out_ ) ;
@ -1622,6 +1625,7 @@ struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
template < typename Char >
FMT_CONSTEXPR void on_text ( const Char * , const Char * ) { }
FMT_CONSTEXPR void on_day_of_year ( ) { }
FMT_CONSTEXPR void on_24_hour ( numeric_system , pad_type ) { }
FMT_CONSTEXPR void on_12_hour ( numeric_system , pad_type ) { }
FMT_CONSTEXPR void on_minute ( numeric_system , pad_type ) { }
@ -1640,16 +1644,16 @@ struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
template < typename T ,
FMT_ENABLE_IF ( std : : is_integral < T > : : value & & has_isfinite < T > : : value ) >
inline bool isfinite ( T ) {
inline auto isfinite ( T ) - > bool {
return true ;
}
template < typename T , FMT_ENABLE_IF ( std : : is_integral < T > : : value ) >
inline T mod ( T x , int y ) {
inline auto mod ( T x , int y ) - > T {
return x % static_cast < T > ( y ) ;
}
template < typename T , FMT_ENABLE_IF ( std : : is_floating_point < T > : : value ) >
inline T mod ( T x , int y ) {
inline auto mod ( T x , int y ) - > T {
return std : : fmod ( x , static_cast < T > ( y ) ) ;
}
@ -1664,49 +1668,38 @@ template <typename T> struct make_unsigned_or_unchanged<T, true> {
using type = typename std : : make_unsigned < T > : : type ;
} ;
# if FMT_SAFE_DURATION_CAST
// throwing version of safe_duration_cast
template < typename To , typename FromRep , typename FromPeriod >
To fmt_safe_duration_cast ( std : : chrono : : duration < FromRep , FromPeriod > from ) {
int ec ;
To to = safe_duration_cast : : safe_duration_cast < To > ( from , ec ) ;
if ( ec ) FMT_THROW ( format_error ( " cannot format duration " ) ) ;
return to ;
}
# endif
template < typename Rep , typename Period ,
FMT_ENABLE_IF ( std : : is_integral < Rep > : : value ) >
inline std : : chrono : : duration < Rep , std: : milli > get_milliseconds (
std : : chrono : : duration < Rep , Period> d ) {
inline auto get_milliseconds ( std : : chrono : : duration < Rep , Period > d )
- > std : : chrono : : duration < Rep , std : : milli > {
// this may overflow and/or the result may not fit in the
// target type.
# if FMT_SAFE_DURATION_CAST
using CommonSecondsType =
typename std : : common_type < decltype ( d ) , std : : chrono : : seconds > : : type ;
const auto d_as_common = fmt_ safe_ duration_cast< CommonSecondsType > ( d ) ;
const auto d_as_common = fmt_duration_cast < CommonSecondsType > ( d ) ;
const auto d_as_whole_seconds =
fmt_ safe_ duration_cast< std : : chrono : : seconds > ( d_as_common ) ;
fmt_ duration_cast< std : : chrono : : seconds > ( d_as_common ) ;
// this conversion should be nonproblematic
const auto diff = d_as_common - d_as_whole_seconds ;
const auto ms =
fmt_ safe_ duration_cast< std : : chrono : : duration < Rep , std : : milli > > ( diff ) ;
fmt_ duration_cast< std : : chrono : : duration < Rep , std : : milli > > ( diff ) ;
return ms ;
# else
auto s = std: : chrono : : duration_cast< std : : chrono : : seconds > ( d ) ;
return std: : chrono : : duration_cast< std : : chrono : : milliseconds > ( d - s ) ;
auto s = fmt_ duration_cast< std : : chrono : : seconds > ( d ) ;
return fmt_ duration_cast< std : : chrono : : milliseconds > ( d - s ) ;
# endif
}
template < typename Char , typename Rep , typename OutputIt ,
FMT_ENABLE_IF ( std : : is_integral < Rep > : : value ) >
OutputIt format_duration_value ( OutputIt out , Rep val , int ) {
auto format_duration_value ( OutputIt out , Rep val , int ) - > OutputIt {
return write < Char > ( out , val ) ;
}
template < typename Char , typename Rep , typename OutputIt ,
FMT_ENABLE_IF ( std : : is_floating_point < Rep > : : value ) >
OutputIt format_duration_value ( OutputIt out , Rep val , int precision ) {
auto format_duration_value ( OutputIt out , Rep val , int precision ) - > OutputIt {
auto specs = format_specs < Char > ( ) ;
specs . precision = precision ;
specs . type = precision > = 0 ? presentation_type : : fixed_lower
@ -1715,12 +1708,12 @@ OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
}
template < typename Char , typename OutputIt >
OutputIt copy_unit ( string_view unit , OutputIt out , Char ) {
auto copy_unit ( string_view unit , OutputIt out , Char ) - > OutputIt {
return std : : copy ( unit . begin ( ) , unit . end ( ) , out ) ;
}
template < typename OutputIt >
OutputIt copy_unit ( string_view unit , OutputIt out , wchar_t ) {
auto copy_unit ( string_view unit , OutputIt out , wchar_t ) - > OutputIt {
// This works when wchar_t is UTF-32 because units only contain characters
// that have the same representation in UTF-16 and UTF-32.
utf8_to_utf16 u ( unit ) ;
@ -1728,7 +1721,7 @@ OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) {
}
template < typename Char , typename Period , typename OutputIt >
OutputIt format_duration_unit ( OutputIt out ) {
auto format_duration_unit ( OutputIt out ) - > OutputIt {
if ( const char * unit = get_units < Period > ( ) )
return copy_unit ( string_view ( unit ) , out , Char ( ) ) ;
* out + + = ' [ ' ;
@ -1795,18 +1788,12 @@ struct chrono_formatter {
// this may overflow and/or the result may not fit in the
// target type.
# if FMT_SAFE_DURATION_CAST
// might need checked conversion (rep!=Rep)
auto tmpval = std : : chrono : : duration < rep , Period > ( val ) ;
s = fmt_safe_duration_cast < seconds > ( tmpval ) ;
# else
s = std : : chrono : : duration_cast < seconds > (
std : : chrono : : duration < rep , Period > ( val ) ) ;
# endif
s = fmt_duration_cast < seconds > ( std : : chrono : : duration < rep , Period > ( val ) ) ;
}
// returns true if nan or inf, writes to out.
bool handle_nan_inf ( ) {
auto handle_nan_inf ( ) - > bool {
if ( isfinite ( val ) ) {
return false ;
}
@ -1823,17 +1810,22 @@ struct chrono_formatter {
return true ;
}
Rep hour ( ) const { return static_cast < Rep > ( mod ( ( s . count ( ) / 3600 ) , 24 ) ) ; }
auto days ( ) const - > Rep { return static_cast < Rep > ( s . count ( ) / 86400 ) ; }
auto hour ( ) const - > Rep {
return static_cast < Rep > ( mod ( ( s . count ( ) / 3600 ) , 24 ) ) ;
}
Rep hour12 ( ) const {
auto hour12 ( ) const - > Rep {
Rep hour = static_cast < Rep > ( mod ( ( s . count ( ) / 3600 ) , 12 ) ) ;
return hour < = 0 ? 12 : hour ;
}
Rep minute ( ) const { return static_cast < Rep > ( mod ( ( s . count ( ) / 60 ) , 60 ) ) ; }
Rep second ( ) const { return static_cast < Rep > ( mod ( s . count ( ) , 60 ) ) ; }
auto minute ( ) const - > Rep {
return static_cast < Rep > ( mod ( ( s . count ( ) / 60 ) , 60 ) ) ;
}
auto second ( ) const - > Rep { return static_cast < Rep > ( mod ( s . count ( ) , 60 ) ) ; }
std : : tm time ( ) const {
auto time ( ) const - > std : : tm {
auto time = std : : tm ( ) ;
time . tm_hour = to_nonnegative_int ( hour ( ) , 24 ) ;
time . tm_min = to_nonnegative_int ( minute ( ) , 60 ) ;
@ -1901,10 +1893,14 @@ struct chrono_formatter {
void on_dec0_week_of_year ( numeric_system ) { }
void on_dec1_week_of_year ( numeric_system ) { }
void on_iso_week_of_year ( numeric_system ) { }
void on_day_of_year ( ) { }
void on_day_of_month ( numeric_system ) { }
void on_day_of_month_space ( numeric_system ) { }
void on_day_of_year ( ) {
if ( handle_nan_inf ( ) ) return ;
write ( days ( ) , 0 ) ;
}
void on_24_hour ( numeric_system ns , pad_type pad ) {
if ( handle_nan_inf ( ) ) return ;
@ -1997,7 +1993,7 @@ struct chrono_formatter {
}
} ;
FMT_END_DETAIL_NAMESPACE
} // namespace detail
# if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
using weekday = std : : chrono : : weekday ;
@ -2011,7 +2007,7 @@ class weekday {
weekday ( ) = default ;
explicit constexpr weekday ( unsigned wd ) noexcept
: value ( static_cast < unsigned char > ( wd ! = 7 ? wd : 0 ) ) { }
constexpr unsigned c_encoding ( ) const noexcept { return value ; }
constexpr auto c_encoding ( ) const noexcept - > unsigned { return value ; }
} ;
class year_month_day { } ;
@ -2047,80 +2043,67 @@ template <typename Char> struct formatter<weekday, Char> {
template < typename Rep , typename Period , typename Char >
struct formatter < std : : chrono : : duration < Rep , Period > , Char > {
private :
format_specs < Char > specs ;
int precision = - 1 ;
using arg_ref_type = detail : : arg_ref < Char > ;
arg_ref_type width_ref ;
arg_ref_type precision_ref ;
bool localized = false ;
basic_string_view < Char > format_str ;
using duration = std : : chrono : : duration < Rep , Period > ;
using iterator = typename basic_format_parse_context < Char > : : iterator ;
struct parse_range {
iterator begin ;
iterator end ;
} ;
format_specs < Char > specs_ ;
detail : : arg_ref < Char > width_ref_ ;
detail : : arg_ref < Char > precision_ref_ ;
bool localized_ = false ;
basic_string_view < Char > format_str_ ;
FMT_CONSTEXPR parse_range do_parse ( basic_format_parse_context < Char > & ctx ) {
auto begin = ctx . begin ( ) , end = ctx . end ( ) ;
if ( begin = = end | | * begin = = ' } ' ) return { begin , begin } ;
public :
FMT_CONSTEXPR auto parse ( basic_format_parse_context < Char > & ctx )
- > decltype ( ctx . begin ( ) ) {
auto it = ctx . begin ( ) , end = ctx . end ( ) ;
if ( it = = end | | * it = = ' } ' ) return it ;
begin = detail : : parse_align ( begin , end , specs ) ;
if ( begin = = end ) return { begin , begin } ;
it = detail : : parse_align ( it , end , specs_ ) ;
if ( it = = end ) return it ;
begin = detail : : parse_dynamic_spec ( begin , end , specs . width , width_ref , ctx ) ;
if ( begin = = end ) return { begin , begin } ;
it = detail : : parse_dynamic_spec ( it , end , specs_ . width , width_ref_ , ctx ) ;
if ( it = = end ) return it ;
auto checker = detail : : chrono_format_checker ( ) ;
if ( * begin = = ' . ' ) {
if ( * it = = ' . ' ) {
checker . has_precision_integral = ! std : : is_floating_point < Rep > : : value ;
begin =
detail : : parse_precision ( begin , end , precision , precision_ref , ctx ) ;
it = detail : : parse_precision ( it , end , specs_ . precision , precision_ref_ ,
ctx ) ;
}
if ( begin ! = end & & * begin = = ' L ' ) {
+ + begin ;
localized = true ;
if ( it ! = end & & * it = = ' L ' ) {
localized_ = true ;
+ + it ;
}
end = detail : : parse_chrono_format ( begin , end , checker ) ;
return { begin , end } ;
}
public :
FMT_CONSTEXPR auto parse ( basic_format_parse_context < Char > & ctx )
- > decltype ( ctx . begin ( ) ) {
auto range = do_parse ( ctx ) ;
format_str = basic_string_view < Char > (
& * range . begin , detail : : to_unsigned ( range . end - range . begin ) ) ;
return range . end ;
end = detail : : parse_chrono_format ( it , end , checker ) ;
format_str_ = { it , detail : : to_unsigned ( end - it ) } ;
return end ;
}
template < typename FormatContext >
auto format ( const duration & d , FormatContext & ctx ) const
auto format ( std : : chrono : : duration < Rep , Period > d , FormatContext & ctx ) const
- > decltype ( ctx . out ( ) ) {
auto specs_copy = specs ;
auto precision_copy = precision ;
auto begin = format_str . begin ( ) , end = format_str . end ( ) ;
auto specs = specs_ ;
auto precision = specs . precision ;
specs . precision = - 1 ;
auto begin = format_str_ . begin ( ) , end = format_str_ . end ( ) ;
// As a possible future optimization, we could avoid extra copying if width
// is not specified.
basic_memory_buffer < Char > buf ;
auto buf = basic_memory_buffer < Char > ( ) ;
auto out = std : : back_inserter ( buf ) ;
detail : : handle_dynamic_spec < detail : : width_checker > ( specs _copy . width ,
width_ref, ctx) ;
detail : : handle_dynamic_spec < detail : : precision_checker > ( precision _copy ,
precision_ref , ctx ) ;
detail : : handle_dynamic_spec < detail : : width_checker > ( specs . width , width_ref_ ,
ctx) ;
detail : : handle_dynamic_spec < detail : : precision_checker > ( precision ,
precision_ref _ , ctx ) ;
if ( begin = = end | | * begin = = ' } ' ) {
out = detail : : format_duration_value < Char > ( out , d . count ( ) , precision _copy ) ;
out = detail : : format_duration_value < Char > ( out , d . count ( ) , precision ) ;
detail : : format_duration_unit < Char , Period > ( out ) ;
} else {
detail : : chrono_formatter < FormatContext , decltype ( out ) , Rep , Period > f (
ctx , out , d ) ;
f . precision = precision_copy ;
f . localized = localized ;
using chrono_formatter =
detail : : chrono_formatter < FormatContext , decltype ( out ) , Rep , Period > ;
auto f = chrono_formatter ( ctx , out , d ) ;
f . precision = precision ;
f . localized = localized_ ;
detail : : parse_chrono_format ( begin , end , f ) ;
}
return detail : : write (
ctx . out ( ) , basic_string_view < Char > ( buf . data ( ) , buf . size ( ) ) , specs _copy ) ;
ctx . out ( ) , basic_string_view < Char > ( buf . data ( ) , buf . size ( ) ) , specs ) ;
}
} ;
@ -2128,34 +2111,33 @@ template <typename Char, typename Duration>
struct formatter < std : : chrono : : time_point < std : : chrono : : system_clock , Duration > ,
Char > : formatter < std : : tm , Char > {
FMT_CONSTEXPR formatter ( ) {
this - > format_str = detail : : string_literal < Char , ' % ' , ' F ' , ' ' , ' % ' , ' T ' > { } ;
this - > format_str _ = detail : : string_literal < Char , ' % ' , ' F ' , ' ' , ' % ' , ' T ' > { } ;
}
template < typename FormatContext >
auto format ( std : : chrono : : time_point < std : : chrono : : system_clock , Duration > val ,
FormatContext & ctx ) const - > decltype ( ctx . out ( ) ) {
using period = typename Duration : : period ;
if ( period : : num ! = 1 | | period : : den ! = 1 | |
std : : is_floating_point < typename Duration : : rep > : : value ) {
if ( detail : : const_check (
period : : num ! = 1 | | period : : den ! = 1 | |
std : : is_floating_point < typename Duration : : rep > : : value ) ) {
const auto epoch = val . time_since_epoch ( ) ;
auto subsecs = std: : chrono : : duration_cast< Duration > (
epoch - std: : chrono : : duration_cast< std : : chrono : : seconds > ( epoch ) ) ;
auto subsecs = detail: : fmt_ duration_cast< Duration > (
epoch - detail: : fmt_ duration_cast< std : : chrono : : seconds > ( epoch ) ) ;
if ( subsecs . count ( ) < 0 ) {
auto second = std : : chrono : : seconds ( 1 ) ;
auto second =
detail : : fmt_duration_cast < Duration > ( std : : chrono : : seconds ( 1 ) ) ;
if ( epoch . count ( ) < ( ( Duration : : min ) ( ) + second ) . count ( ) )
FMT_THROW ( format_error ( " duration is too small " ) ) ;
subsecs + = second ;
val - = second ;
}
return formatter < std : : tm , Char > : : do_format (
gmtime ( std : : chrono : : time_point_cast < std : : chrono : : seconds > ( val ) ) , ctx ,
& subsecs ) ;
return formatter < std : : tm , Char > : : do_format ( gmtime ( val ) , ctx , & subsecs ) ;
}
return formatter < std : : tm , Char > : : format (
gmtime ( std : : chrono : : time_point_cast < std : : chrono : : seconds > ( val ) ) , ctx ) ;
return formatter < std : : tm , Char > : : format ( gmtime ( val ) , ctx ) ;
}
} ;
@ -2164,7 +2146,7 @@ template <typename Char, typename Duration>
struct formatter < std : : chrono : : local_time < Duration > , Char >
: formatter < std : : tm , Char > {
FMT_CONSTEXPR formatter ( ) {
this - > format_str = detail : : string_literal < Char , ' % ' , ' F ' , ' ' , ' % ' , ' T ' > { } ;
this - > format_str _ = detail : : string_literal < Char , ' % ' , ' F ' , ' ' , ' % ' , ' T ' > { } ;
}
template < typename FormatContext >
@ -2174,17 +2156,13 @@ struct formatter<std::chrono::local_time<Duration>, Char>
if ( period : : num ! = 1 | | period : : den ! = 1 | |
std : : is_floating_point < typename Duration : : rep > : : value ) {
const auto epoch = val . time_since_epoch ( ) ;
const auto subsecs = std: : chrono : : duration_cast< Duration > (
epoch - std: : chrono : : duration_cast< std : : chrono : : seconds > ( epoch ) ) ;
const auto subsecs = detail: : fmt_ duration_cast< Duration > (
epoch - detail: : fmt_ duration_cast< std : : chrono : : seconds > ( epoch ) ) ;
return formatter < std : : tm , Char > : : do_format (
localtime ( std : : chrono : : time_point_cast < std : : chrono : : seconds > ( val ) ) ,
ctx , & subsecs ) ;
return formatter < std : : tm , Char > : : do_format ( localtime ( val ) , ctx , & subsecs ) ;
}
return formatter < std : : tm , Char > : : format (
localtime ( std : : chrono : : time_point_cast < std : : chrono : : seconds > ( val ) ) ,
ctx ) ;
return formatter < std : : tm , Char > : : format ( localtime ( val ) , ctx ) ;
}
} ;
# endif
@ -2207,51 +2185,46 @@ struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,
template < typename Char > struct formatter < std : : tm , Char > {
private :
format_specs < Char > specs ;
detail : : arg_ref < Char > width_ref ;
format_specs < Char > specs _ ;
detail : : arg_ref < Char > width_ref _ ;
protected :
basic_string_view < Char > format_str ;
FMT_CONSTEXPR auto do_parse ( basic_format_parse_context < Char > & ctx )
- > decltype ( ctx . begin ( ) ) {
auto begin = ctx . begin ( ) , end = ctx . end ( ) ;
if ( begin = = end | | * begin = = ' } ' ) return begin ;
begin = detail : : parse_align ( begin , end , specs ) ;
if ( begin = = end ) return end ;
begin = detail : : parse_dynamic_spec ( begin , end , specs . width , width_ref , ctx ) ;
if ( begin = = end ) return end ;
end = detail : : parse_chrono_format ( begin , end , detail : : tm_format_checker ( ) ) ;
// Replace default format_str only if the new spec is not empty.
if ( end ! = begin ) format_str = { begin , detail : : to_unsigned ( end - begin ) } ;
return end ;
}
basic_string_view < Char > format_str_ ;
template < typename FormatContext , typename Duration >
auto do_format ( const std : : tm & tm , FormatContext & ctx ,
const Duration * subsecs ) const - > decltype ( ctx . out ( ) ) {
auto specs _copy = specs ;
basic_memory_buffer < Char > buf ;
auto specs = specs_ ;
auto buf = basic_memory_buffer < Char > ( ) ;
auto out = std : : back_inserter ( buf ) ;
detail : : handle_dynamic_spec < detail : : width_checker > ( specs _copy . width ,
width_ref, ctx) ;
detail : : handle_dynamic_spec < detail : : width_checker > ( specs . width , width_ref_ ,
ctx ) ;
const auto loc_ref = ctx . locale ( ) ;
auto loc_ref = ctx . locale ( ) ;
detail : : get_locale loc ( static_cast < bool > ( loc_ref ) , loc_ref ) ;
auto w =
detail : : tm_writer < decltype ( out ) , Char , Duration > ( loc , out , tm , subsecs ) ;
detail : : parse_chrono_format ( format_str . begin ( ) , format_str . end ( ) , w ) ;
detail : : parse_chrono_format ( format_str_ . begin ( ) , format_str_ . end ( ) , w ) ;
return detail : : write (
ctx . out ( ) , basic_string_view < Char > ( buf . data ( ) , buf . size ( ) ) , specs _copy ) ;
ctx . out ( ) , basic_string_view < Char > ( buf . data ( ) , buf . size ( ) ) , specs ) ;
}
public :
FMT_CONSTEXPR auto parse ( basic_format_parse_context < Char > & ctx )
- > decltype ( ctx . begin ( ) ) {
return this - > do_parse ( ctx ) ;
auto it = ctx . begin ( ) , end = ctx . end ( ) ;
if ( it = = end | | * it = = ' } ' ) return it ;
it = detail : : parse_align ( it , end , specs_ ) ;
if ( it = = end ) return it ;
it = detail : : parse_dynamic_spec ( it , end , specs_ . width , width_ref_ , ctx ) ;
if ( it = = end ) return it ;
end = detail : : parse_chrono_format ( it , end , detail : : tm_format_checker ( ) ) ;
// Replace the default format_str only if the new spec is not empty.
if ( end ! = it ) format_str_ = { it , detail : : to_unsigned ( end - it ) } ;
return end ;
}
template < typename FormatContext >