Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
spdlog
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
spdlog
Commits
23c2c00d
Commit
23c2c00d
authored
Aug 26, 2020
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bumb fmt version to 7.0.3
parent
fa501b46
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
2259 additions
and
2067 deletions
+2259
-2067
bench/async_bench.cpp
bench/async_bench.cpp
+12
-11
bench/bench.cpp
bench/bench.cpp
+9
-6
include/spdlog/fmt/bundled/chrono.h
include/spdlog/fmt/bundled/chrono.h
+66
-62
include/spdlog/fmt/bundled/color.h
include/spdlog/fmt/bundled/color.h
+35
-37
include/spdlog/fmt/bundled/compile.h
include/spdlog/fmt/bundled/compile.h
+173
-103
include/spdlog/fmt/bundled/core.h
include/spdlog/fmt/bundled/core.h
+528
-442
include/spdlog/fmt/bundled/format-inl.h
include/spdlog/fmt/bundled/format-inl.h
+114
-64
include/spdlog/fmt/bundled/format.h
include/spdlog/fmt/bundled/format.h
+1152
-1071
include/spdlog/fmt/bundled/locale.h
include/spdlog/fmt/bundled/locale.h
+16
-16
include/spdlog/fmt/bundled/ostream.h
include/spdlog/fmt/bundled/ostream.h
+11
-10
include/spdlog/fmt/bundled/posix.h
include/spdlog/fmt/bundled/posix.h
+1
-1
include/spdlog/fmt/bundled/printf.h
include/spdlog/fmt/bundled/printf.h
+86
-61
include/spdlog/fmt/bundled/ranges.h
include/spdlog/fmt/bundled/ranges.h
+35
-36
src/fmt.cpp
src/fmt.cpp
+21
-147
No files found.
bench/async_bench.cpp
View file @
23c2c00d
...
...
@@ -9,7 +9,7 @@
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/
sinks/stdout_color_sinks
.h"
#include "spdlog/
fmt/bundled/locale
.h"
#include "utils.h"
#include <atomic>
...
...
@@ -29,7 +29,7 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996) // disable fopen warning under msvc
#endif
// _MSC_VER
#endif // _MSC_VER
int
count_lines
(
const
char
*
filename
)
{
...
...
@@ -48,14 +48,14 @@ int count_lines(const char *filename)
void
verify_file
(
const
char
*
filename
,
int
expected_count
)
{
spdlog
::
info
(
"Verifying {} to contain {
:n
} line.."
,
filename
,
expected_count
);
spdlog
::
info
(
"Verifying {} to contain {} line.."
,
filename
,
expected_count
);
auto
count
=
count_lines
(
filename
);
if
(
count
!=
expected_count
)
{
spdlog
::
error
(
"Test failed. {} has {
:n} lines instead of {:n
}"
,
filename
,
count
,
expected_count
);
spdlog
::
error
(
"Test failed. {} has {
} lines instead of {
}"
,
filename
,
count
,
expected_count
);
exit
(
1
);
}
spdlog
::
info
(
"Line count OK ({
:n
})
\n
"
,
count
);
spdlog
::
info
(
"Line count OK ({})
\n
"
,
count
);
}
#ifdef _MSC_VER
...
...
@@ -98,11 +98,12 @@ int main(int argc, char *argv[])
auto
slot_size
=
sizeof
(
spdlog
::
details
::
async_msg
);
spdlog
::
info
(
"-------------------------------------------------"
);
spdlog
::
info
(
"Messages : {:n}"
,
howmany
);
spdlog
::
info
(
"Threads : {:n}"
,
threads
);
spdlog
::
info
(
"Queue : {:n} slots"
,
queue_size
);
spdlog
::
info
(
"Queue memory : {:n} x {} = {:n} KB "
,
queue_size
,
slot_size
,
(
queue_size
*
slot_size
)
/
1024
);
spdlog
::
info
(
"Total iters : {:n}"
,
iters
);
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Messages : {:L}"
,
howmany
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Threads : {:L}"
,
threads
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Queue : {:L} slots"
,
queue_size
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Queue memory : {:L} x {:L} = {:L} KB "
,
queue_size
,
slot_size
,
(
queue_size
*
slot_size
)
/
1024
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Total iters : {:L}"
,
iters
));
spdlog
::
info
(
"-------------------------------------------------"
);
const
char
*
filename
=
"logs/basic_async.log"
;
...
...
@@ -175,5 +176,5 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> logger, int thread_co
auto
delta
=
high_resolution_clock
::
now
()
-
start
;
auto
delta_d
=
duration_cast
<
duration
<
double
>>
(
delta
).
count
();
spdlog
::
info
(
"Elapsed: {} secs
\t
{:n}/sec"
,
delta_d
,
int
(
howmany
/
delta_d
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Elapsed: {} secs
\t
{:L}/sec"
,
delta_d
,
int
(
howmany
/
delta_d
)
));
}
bench/bench.cpp
View file @
23c2c00d
...
...
@@ -11,6 +11,7 @@
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/fmt/bundled/locale.h"
#include "utils.h"
#include <atomic>
...
...
@@ -32,7 +33,7 @@ static const int max_threads = 1000;
void
bench_threaded_logging
(
size_t
threads
,
int
iters
)
{
spdlog
::
info
(
"**************************************************************"
);
spdlog
::
info
(
"Multi threaded: {:n} threads, {:n} messages"
,
threads
,
iters
);
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Multi threaded: {:L} threads, {:L} messages"
,
threads
,
iters
)
);
spdlog
::
info
(
"**************************************************************"
);
auto
basic_mt
=
spdlog
::
basic_logger_mt
(
"basic_mt"
,
"logs/basic_mt.log"
,
true
);
...
...
@@ -68,7 +69,7 @@ void bench_threaded_logging(size_t threads, int iters)
void
bench_single_threaded
(
int
iters
)
{
spdlog
::
info
(
"**************************************************************"
);
spdlog
::
info
(
"Single threaded: {:n} messages"
,
iters
);
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"Single threaded: {} messages"
,
iters
)
);
spdlog
::
info
(
"**************************************************************"
);
auto
basic_st
=
spdlog
::
basic_logger_st
(
"basic_st"
,
"logs/basic_st.log"
,
true
);
...
...
@@ -152,7 +153,8 @@ void bench(int howmany, std::shared_ptr<spdlog::logger> log)
auto
delta
=
high_resolution_clock
::
now
()
-
start
;
auto
delta_d
=
duration_cast
<
duration
<
double
>>
(
delta
).
count
();
spdlog
::
info
(
"{:<30} Elapsed: {:0.2f} secs {:>16n}/sec"
,
log
->
name
(),
delta_d
,
int
(
howmany
/
delta_d
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"{:<30} Elapsed: {:0.2f} secs {:>16L}/sec"
,
log
->
name
(),
delta_d
,
int
(
howmany
/
delta_d
)));
spdlog
::
drop
(
log
->
name
());
}
...
...
@@ -182,7 +184,8 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t thread_co
auto
delta
=
high_resolution_clock
::
now
()
-
start
;
auto
delta_d
=
duration_cast
<
duration
<
double
>>
(
delta
).
count
();
spdlog
::
info
(
"{:<30} Elapsed: {:0.2f} secs {:>16n}/sec"
,
log
->
name
(),
delta_d
,
int
(
howmany
/
delta_d
));
spdlog
::
info
(
fmt
::
format
(
std
::
locale
(
"en_US.UTF-8"
),
"{:<30} Elapsed: {:0.2f} secs {:>16L}/sec"
,
log
->
name
(),
delta_d
,
int
(
howmany
/
delta_d
)));
spdlog
::
drop
(
log
->
name
());
}
...
...
@@ -205,7 +208,7 @@ void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log)
auto delta_d = duration_cast<duration<double>>(delta).count();
spdlog::drop(log->name());
spdlog::set_default_logger(std::move(orig_default));
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16
n
}/sec", log->name(), delta_d, int(howmany / delta_d));
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany / delta_d));
}
void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log)
...
...
@@ -232,7 +235,7 @@ void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log)
auto delta_d = duration_cast<duration<double>>(delta).count();
spdlog::drop(log->name());
spdlog::set_default_logger(std::move(orig_default));
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16
n
}/sec", log->name(), delta_d, int(howmany / delta_d));
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany / delta_d));
}
*/
\ No newline at end of file
include/spdlog/fmt/bundled/chrono.h
View file @
23c2c00d
...
...
@@ -48,7 +48,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// From fits in To without any problem.
}
else
{
// From does not always fit in To, resort to a dynamic check.
if
(
from
<
T
::
min
()
||
from
>
T
::
max
())
{
if
(
from
<
(
T
::
min
)()
||
from
>
(
T
::
max
)
())
{
// outside range.
ec
=
1
;
return
{};
...
...
@@ -74,7 +74,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
if
(
F
::
is_signed
&&
!
T
::
is_signed
)
{
// From may be negative, not allowed!
if
(
fmt
::
interna
l
::
is_negative
(
from
))
{
if
(
fmt
::
detai
l
::
is_negative
(
from
))
{
ec
=
1
;
return
{};
}
...
...
@@ -84,7 +84,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// yes, From always fits in To.
}
else
{
// from may not fit in To, we have to do a dynamic check
if
(
from
>
static_cast
<
From
>
(
T
::
max
()))
{
if
(
from
>
static_cast
<
From
>
(
(
T
::
max
)
()))
{
ec
=
1
;
return
{};
}
...
...
@@ -97,7 +97,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// yes, From always fits in To.
}
else
{
// from may not fit in To, we have to do a dynamic check
if
(
from
>
static_cast
<
From
>
(
T
::
max
()))
{
if
(
from
>
static_cast
<
From
>
(
(
T
::
max
)
()))
{
// outside range.
ec
=
1
;
return
{};
...
...
@@ -141,7 +141,7 @@ FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
// catch the only happy case
if
(
std
::
isfinite
(
from
))
{
if
(
from
>=
T
::
lowest
()
&&
from
<=
T
::
max
())
{
if
(
from
>=
T
::
lowest
()
&&
from
<=
(
T
::
max
)
())
{
return
static_cast
<
To
>
(
from
);
}
// not within range.
...
...
@@ -195,12 +195,13 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
}
// multiply with Factor::num without overflow or underflow
if
(
Factor
::
num
!=
1
)
{
const
auto
max1
=
interna
l
::
max_value
<
IntermediateRep
>
()
/
Factor
::
num
;
const
auto
max1
=
detai
l
::
max_value
<
IntermediateRep
>
()
/
Factor
::
num
;
if
(
count
>
max1
)
{
ec
=
1
;
return
{};
}
const
auto
min1
=
std
::
numeric_limits
<
IntermediateRep
>::
min
()
/
Factor
::
num
;
const
auto
min1
=
(
std
::
numeric_limits
<
IntermediateRep
>::
min
)()
/
Factor
::
num
;
if
(
count
<
min1
)
{
ec
=
1
;
return
{};
...
...
@@ -269,7 +270,7 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
// multiply with Factor::num without overflow or underflow
if
(
Factor
::
num
!=
1
)
{
constexpr
auto
max1
=
interna
l
::
max_value
<
IntermediateRep
>
()
/
constexpr
auto
max1
=
detai
l
::
max_value
<
IntermediateRep
>
()
/
static_cast
<
IntermediateRep
>
(
Factor
::
num
);
if
(
count
>
max1
)
{
ec
=
1
;
...
...
@@ -306,12 +307,12 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
namespace
interna
l
{
namespace
detai
l
{
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
<>
();
}
}
// namespace
interna
l
}
// namespace
detai
l
// Thread-safe replacement for std::localtime
inline
std
::
tm
localtime
(
std
::
time_t
time
)
{
...
...
@@ -322,22 +323,22 @@ inline std::tm localtime(std::time_t time) {
dispatcher
(
std
::
time_t
t
)
:
time_
(
t
)
{}
bool
run
()
{
using
namespace
fmt
::
interna
l
;
using
namespace
fmt
::
detai
l
;
return
handle
(
localtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
nullptr
;
}
bool
handle
(
interna
l
::
null
<>
)
{
using
namespace
fmt
::
interna
l
;
bool
handle
(
detai
l
::
null
<>
)
{
using
namespace
fmt
::
detai
l
;
return
fallback
(
localtime_s
(
&
tm_
,
&
time_
));
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
#if !FMT_MSC_VER
bool
fallback
(
interna
l
::
null
<>
)
{
using
namespace
fmt
::
interna
l
;
bool
fallback
(
detai
l
::
null
<>
)
{
using
namespace
fmt
::
detai
l
;
std
::
tm
*
tm
=
std
::
localtime
(
&
time_
);
if
(
tm
)
tm_
=
*
tm
;
return
tm
!=
nullptr
;
...
...
@@ -359,21 +360,21 @@ inline std::tm gmtime(std::time_t time) {
dispatcher
(
std
::
time_t
t
)
:
time_
(
t
)
{}
bool
run
()
{
using
namespace
fmt
::
interna
l
;
using
namespace
fmt
::
detai
l
;
return
handle
(
gmtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
nullptr
;
}
bool
handle
(
interna
l
::
null
<>
)
{
using
namespace
fmt
::
interna
l
;
bool
handle
(
detai
l
::
null
<>
)
{
using
namespace
fmt
::
detai
l
;
return
fallback
(
gmtime_s
(
&
tm_
,
&
time_
));
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
#if !FMT_MSC_VER
bool
fallback
(
interna
l
::
null
<>
)
{
bool
fallback
(
detai
l
::
null
<>
)
{
std
::
tm
*
tm
=
std
::
gmtime
(
&
time_
);
if
(
tm
)
tm_
=
*
tm
;
return
tm
!=
nullptr
;
...
...
@@ -386,17 +387,17 @@ inline std::tm gmtime(std::time_t time) {
return
gt
.
tm_
;
}
namespace
interna
l
{
inline
s
td
::
size_t
strftime
(
char
*
str
,
std
::
size_t
count
,
const
char
*
format
,
const
std
::
tm
*
time
)
{
namespace
detai
l
{
inline
s
ize_t
strftime
(
char
*
str
,
size_t
count
,
const
char
*
format
,
const
std
::
tm
*
time
)
{
return
std
::
strftime
(
str
,
count
,
format
,
time
);
}
inline
s
td
::
size_t
strftime
(
wchar_t
*
str
,
std
::
size_t
coun
t
,
const
wchar_t
*
format
,
const
std
::
tm
*
time
)
{
inline
s
ize_t
strftime
(
wchar_t
*
str
,
size_t
count
,
const
wchar_t
*
forma
t
,
const
std
::
tm
*
time
)
{
return
std
::
wcsftime
(
str
,
count
,
format
,
time
);
}
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
Char
>
struct
formatter
<
std
::
tm
,
Char
>
{
template
<
typename
ParseContext
>
...
...
@@ -405,7 +406,7 @@ template <typename Char> struct formatter<std::tm, Char> {
if
(
it
!=
ctx
.
end
()
&&
*
it
==
':'
)
++
it
;
auto
end
=
it
;
while
(
end
!=
ctx
.
end
()
&&
*
end
!=
'}'
)
++
end
;
tm_format
.
reserve
(
interna
l
::
to_unsigned
(
end
-
it
+
1
));
tm_format
.
reserve
(
detai
l
::
to_unsigned
(
end
-
it
+
1
));
tm_format
.
append
(
it
,
end
);
tm_format
.
push_back
(
'\0'
);
return
end
;
...
...
@@ -414,11 +415,10 @@ template <typename Char> struct formatter<std::tm, Char> {
template
<
typename
FormatContext
>
auto
format
(
const
std
::
tm
&
tm
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
basic_memory_buffer
<
Char
>
buf
;
s
td
::
s
ize_t
start
=
buf
.
size
();
size_t
start
=
buf
.
size
();
for
(;;)
{
std
::
size_t
size
=
buf
.
capacity
()
-
start
;
std
::
size_t
count
=
internal
::
strftime
(
&
buf
[
start
],
size
,
&
tm_format
[
0
],
&
tm
);
size_t
size
=
buf
.
capacity
()
-
start
;
size_t
count
=
detail
::
strftime
(
&
buf
[
start
],
size
,
&
tm_format
[
0
],
&
tm
);
if
(
count
!=
0
)
{
buf
.
resize
(
start
+
count
);
break
;
...
...
@@ -430,7 +430,7 @@ template <typename Char> struct formatter<std::tm, Char> {
// https://github.com/fmtlib/fmt/issues/367
break
;
}
const
s
td
::
s
ize_t
MIN_GROWTH
=
10
;
const
size_t
MIN_GROWTH
=
10
;
buf
.
reserve
(
buf
.
capacity
()
+
(
size
>
MIN_GROWTH
?
size
:
MIN_GROWTH
));
}
return
std
::
copy
(
buf
.
begin
(),
buf
.
end
(),
ctx
.
out
());
...
...
@@ -439,7 +439,7 @@ template <typename Char> struct formatter<std::tm, Char> {
basic_memory_buffer
<
Char
>
tm_format
;
};
namespace
interna
l
{
namespace
detai
l
{
template
<
typename
Period
>
FMT_CONSTEXPR
const
char
*
get_units
()
{
return
nullptr
;
}
...
...
@@ -768,19 +768,25 @@ OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
return
format_to
(
out
,
std
::
is_floating_point
<
Rep
>::
value
?
fp_f
:
format
,
val
);
}
template
<
typename
Char
,
typename
OutputIt
>
OutputIt
copy_unit
(
string_view
unit
,
OutputIt
out
,
Char
)
{
return
std
::
copy
(
unit
.
begin
(),
unit
.
end
(),
out
);
}
template
<
typename
OutputIt
>
OutputIt
copy_unit
(
string_view
unit
,
OutputIt
out
,
wchar_t
)
{
// 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
);
return
std
::
copy
(
u
.
c_str
(),
u
.
c_str
()
+
u
.
size
(),
out
);
}
template
<
typename
Char
,
typename
Period
,
typename
OutputIt
>
OutputIt
format_duration_unit
(
OutputIt
out
)
{
if
(
const
char
*
unit
=
get_units
<
Period
>
())
{
string_view
s
(
unit
);
if
(
const_check
(
std
::
is_same
<
Char
,
wchar_t
>
()))
{
utf8_to_utf16
u
(
s
);
return
std
::
copy
(
u
.
c_str
(),
u
.
c_str
()
+
u
.
size
(),
out
);
}
return
std
::
copy
(
s
.
begin
(),
s
.
end
(),
out
);
}
if
(
const
char
*
unit
=
get_units
<
Period
>
())
return
copy_unit
(
string_view
(
unit
),
out
,
Char
());
const
Char
num_f
[]
=
{
'['
,
'{'
,
'}'
,
']'
,
's'
,
0
};
if
(
Period
::
den
==
1
)
return
format_to
(
out
,
num_f
,
Period
::
num
);
if
(
const_check
(
Period
::
den
==
1
)
)
return
format_to
(
out
,
num_f
,
Period
::
num
);
const
Char
num_def_f
[]
=
{
'['
,
'{'
,
'}'
,
'/'
,
'{'
,
'}'
,
']'
,
's'
,
0
};
return
format_to
(
out
,
num_def_f
,
Period
::
num
,
Period
::
den
);
}
...
...
@@ -874,9 +880,9 @@ struct chrono_formatter {
if
(
isnan
(
value
))
return
write_nan
();
uint32_or_64_or_128_t
<
int
>
n
=
to_unsigned
(
to_nonnegative_int
(
value
,
max_value
<
int
>
()));
int
num_digits
=
interna
l
::
count_digits
(
n
);
int
num_digits
=
detai
l
::
count_digits
(
n
);
if
(
width
>
num_digits
)
out
=
std
::
fill_n
(
out
,
width
-
num_digits
,
'0'
);
out
=
format_decimal
<
char_type
>
(
out
,
n
,
num_digits
);
out
=
format_decimal
<
char_type
>
(
out
,
n
,
num_digits
)
.
end
;
}
void
write_nan
()
{
std
::
copy_n
(
"nan"
,
3
,
out
);
}
...
...
@@ -1004,14 +1010,14 @@ struct chrono_formatter {
out
=
format_duration_unit
<
char_type
,
Period
>
(
out
);
}
};
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
Rep
,
typename
Period
,
typename
Char
>
struct
formatter
<
std
::
chrono
::
duration
<
Rep
,
Period
>
,
Char
>
{
private:
basic_format_specs
<
Char
>
specs
;
int
precision
;
using
arg_ref_type
=
interna
l
::
arg_ref
<
Char
>
;
using
arg_ref_type
=
detai
l
::
arg_ref
<
Char
>
;
arg_ref_type
width_ref
;
arg_ref_type
precision_ref
;
mutable
basic_string_view
<
Char
>
format_str
;
...
...
@@ -1032,7 +1038,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
return
arg_ref_type
(
arg_id
);
}
FMT_CONSTEXPR
arg_ref_type
make_arg_ref
(
interna
l
::
auto_id
)
{
FMT_CONSTEXPR
arg_ref_type
make_arg_ref
(
detai
l
::
auto_id
)
{
return
arg_ref_type
(
context
.
next_arg_id
());
}
...
...
@@ -1062,17 +1068,17 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
auto
begin
=
ctx
.
begin
(),
end
=
ctx
.
end
();
if
(
begin
==
end
||
*
begin
==
'}'
)
return
{
begin
,
begin
};
spec_handler
handler
{
*
this
,
ctx
,
format_str
};
begin
=
interna
l
::
parse_align
(
begin
,
end
,
handler
);
begin
=
detai
l
::
parse_align
(
begin
,
end
,
handler
);
if
(
begin
==
end
)
return
{
begin
,
begin
};
begin
=
interna
l
::
parse_width
(
begin
,
end
,
handler
);
begin
=
detai
l
::
parse_width
(
begin
,
end
,
handler
);
if
(
begin
==
end
)
return
{
begin
,
begin
};
if
(
*
begin
==
'.'
)
{
if
(
std
::
is_floating_point
<
Rep
>::
value
)
begin
=
interna
l
::
parse_precision
(
begin
,
end
,
handler
);
begin
=
detai
l
::
parse_precision
(
begin
,
end
,
handler
);
else
handler
.
on_error
(
"precision not allowed for this argument type"
);
}
end
=
parse_chrono_format
(
begin
,
end
,
interna
l
::
chrono_format_checker
());
end
=
parse_chrono_format
(
begin
,
end
,
detai
l
::
chrono_format_checker
());
return
{
begin
,
end
};
}
...
...
@@ -1083,7 +1089,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
->
decltype
(
ctx
.
begin
())
{
auto
range
=
do_parse
(
ctx
);
format_str
=
basic_string_view
<
Char
>
(
&*
range
.
begin
,
interna
l
::
to_unsigned
(
range
.
end
-
range
.
begin
));
&*
range
.
begin
,
detai
l
::
to_unsigned
(
range
.
end
-
range
.
begin
));
return
range
.
end
;
}
...
...
@@ -1094,23 +1100,21 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
// is not specified.
basic_memory_buffer
<
Char
>
buf
;
auto
out
=
std
::
back_inserter
(
buf
);
using
range
=
internal
::
output_range
<
decltype
(
ctx
.
out
()),
Char
>
;
internal
::
basic_writer
<
range
>
w
(
range
(
ctx
.
out
()));
internal
::
handle_dynamic_spec
<
internal
::
width_checker
>
(
specs
.
width
,
width_ref
,
ctx
);
internal
::
handle_dynamic_spec
<
internal
::
precision_checker
>
(
precision
,
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
=
interna
l
::
format_duration_value
<
Char
>
(
out
,
d
.
count
(),
precision
);
interna
l
::
format_duration_unit
<
Char
,
Period
>
(
out
);
out
=
detai
l
::
format_duration_value
<
Char
>
(
out
,
d
.
count
(),
precision
);
detai
l
::
format_duration_unit
<
Char
,
Period
>
(
out
);
}
else
{
interna
l
::
chrono_formatter
<
FormatContext
,
decltype
(
out
),
Rep
,
Period
>
f
(
detai
l
::
chrono_formatter
<
FormatContext
,
decltype
(
out
),
Rep
,
Period
>
f
(
ctx
,
out
,
d
);
f
.
precision
=
precision
;
parse_chrono_format
(
begin
,
end
,
f
);
}
w
.
write
(
buf
.
data
(),
buf
.
size
(),
specs
);
return
w
.
out
(
);
return
detail
::
write
(
ctx
.
out
(),
basic_string_view
<
Char
>
(
buf
.
data
(),
buf
.
size
()),
specs
);
}
};
...
...
include/spdlog/fmt/bundled/color.h
View file @
23c2c00d
...
...
@@ -198,7 +198,7 @@ struct rgb {
uint8_t
b
;
};
namespace
interna
l
{
namespace
detai
l
{
// color is a struct of either a rgb color or a terminal color.
struct
color_type
{
...
...
@@ -221,7 +221,7 @@ struct color_type {
uint32_t
rgb_color
;
}
value
;
};
}
// namespace
interna
l
}
// namespace
detai
l
// Experimental text formatting support.
class
text_style
{
...
...
@@ -298,11 +298,11 @@ class text_style {
FMT_CONSTEXPR
bool
has_emphasis
()
const
FMT_NOEXCEPT
{
return
static_cast
<
uint8_t
>
(
ems
)
!=
0
;
}
FMT_CONSTEXPR
interna
l
::
color_type
get_foreground
()
const
FMT_NOEXCEPT
{
FMT_CONSTEXPR
detai
l
::
color_type
get_foreground
()
const
FMT_NOEXCEPT
{
FMT_ASSERT
(
has_foreground
(),
"no foreground specified for this style"
);
return
foreground_color
;
}
FMT_CONSTEXPR
interna
l
::
color_type
get_background
()
const
FMT_NOEXCEPT
{
FMT_CONSTEXPR
detai
l
::
color_type
get_background
()
const
FMT_NOEXCEPT
{
FMT_ASSERT
(
has_background
(),
"no background specified for this style"
);
return
background_color
;
}
...
...
@@ -313,7 +313,7 @@ class text_style {
private:
FMT_CONSTEXPR
text_style
(
bool
is_foreground
,
interna
l
::
color_type
text_color
)
FMT_NOEXCEPT
detai
l
::
color_type
text_color
)
FMT_NOEXCEPT
:
set_foreground_color
(),
set_background_color
(),
ems
()
{
...
...
@@ -326,23 +326,23 @@ class text_style {
}
}
friend
FMT_CONSTEXPR_DECL
text_style
fg
(
interna
l
::
color_type
foreground
)
friend
FMT_CONSTEXPR_DECL
text_style
fg
(
detai
l
::
color_type
foreground
)
FMT_NOEXCEPT
;
friend
FMT_CONSTEXPR_DECL
text_style
bg
(
interna
l
::
color_type
background
)
friend
FMT_CONSTEXPR_DECL
text_style
bg
(
detai
l
::
color_type
background
)
FMT_NOEXCEPT
;
interna
l
::
color_type
foreground_color
;
interna
l
::
color_type
background_color
;
detai
l
::
color_type
foreground_color
;
detai
l
::
color_type
background_color
;
bool
set_foreground_color
;
bool
set_background_color
;
emphasis
ems
;
};
FMT_CONSTEXPR
text_style
fg
(
interna
l
::
color_type
foreground
)
FMT_NOEXCEPT
{
FMT_CONSTEXPR
text_style
fg
(
detai
l
::
color_type
foreground
)
FMT_NOEXCEPT
{
return
text_style
(
/*is_foreground=*/
true
,
foreground
);
}
FMT_CONSTEXPR
text_style
bg
(
interna
l
::
color_type
background
)
FMT_NOEXCEPT
{
FMT_CONSTEXPR
text_style
bg
(
detai
l
::
color_type
background
)
FMT_NOEXCEPT
{
return
text_style
(
/*is_foreground=*/
false
,
background
);
}
...
...
@@ -350,21 +350,21 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
return
text_style
(
lhs
)
|
rhs
;
}
namespace
interna
l
{
namespace
detai
l
{
template
<
typename
Char
>
struct
ansi_color_escape
{
FMT_CONSTEXPR
ansi_color_escape
(
interna
l
::
color_type
text_color
,
FMT_CONSTEXPR
ansi_color_escape
(
detai
l
::
color_type
text_color
,
const
char
*
esc
)
FMT_NOEXCEPT
{
// If we have a terminal color, we need to output another escape code
// sequence.
if
(
!
text_color
.
is_rgb
)
{
bool
is_background
=
esc
==
interna
l
::
data
::
background_color
;
bool
is_background
=
esc
==
detai
l
::
data
::
background_color
;
uint32_t
value
=
text_color
.
value
.
term_color
;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if
(
is_background
)
value
+=
10u
;
s
td
::
s
ize_t
index
=
0
;
size_t
index
=
0
;
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'\x1b'
);
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'['
);
...
...
@@ -398,7 +398,7 @@ template <typename Char> struct ansi_color_escape {
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
strikethrough
))
em_codes
[
3
]
=
9
;
s
td
::
s
ize_t
index
=
0
;
size_t
index
=
0
;
for
(
int
i
=
0
;
i
<
4
;
++
i
)
{
if
(
!
em_codes
[
i
])
continue
;
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'\x1b'
);
...
...
@@ -429,14 +429,14 @@ template <typename Char> struct ansi_color_escape {
template
<
typename
Char
>
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_foreground_color
(
interna
l
::
color_type
foreground
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
foreground
,
interna
l
::
data
::
foreground_color
);
detai
l
::
color_type
foreground
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
foreground
,
detai
l
::
data
::
foreground_color
);
}
template
<
typename
Char
>
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_background_color
(
interna
l
::
color_type
background
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
background
,
interna
l
::
data
::
background_color
);
detai
l
::
color_type
background
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
background
,
detai
l
::
data
::
background_color
);
}
template
<
typename
Char
>
...
...
@@ -455,11 +455,11 @@ inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
}
template
<
typename
Char
>
inline
void
reset_color
(
FILE
*
stream
)
FMT_NOEXCEPT
{
fputs
(
interna
l
::
data
::
reset_color
,
stream
);
fputs
(
detai
l
::
data
::
reset_color
,
stream
);
}
template
<
>
inline
void
reset_color
<
wchar_t
>
(
FILE
*
stream
)
FMT_NOEXCEPT
{
fputs
(
interna
l
::
data
::
wreset_color
,
stream
);
fputs
(
detai
l
::
data
::
wreset_color
,
stream
);
}
template
<
typename
Char
>
...
...
@@ -476,33 +476,31 @@ void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
bool
has_style
=
false
;
if
(
ts
.
has_emphasis
())
{
has_style
=
true
;
auto
emphasis
=
interna
l
::
make_emphasis
<
Char
>
(
ts
.
get_emphasis
());
auto
emphasis
=
detai
l
::
make_emphasis
<
Char
>
(
ts
.
get_emphasis
());
buf
.
append
(
emphasis
.
begin
(),
emphasis
.
end
());
}
if
(
ts
.
has_foreground
())
{
has_style
=
true
;
auto
foreground
=
internal
::
make_foreground_color
<
Char
>
(
ts
.
get_foreground
());
auto
foreground
=
detail
::
make_foreground_color
<
Char
>
(
ts
.
get_foreground
());
buf
.
append
(
foreground
.
begin
(),
foreground
.
end
());
}
if
(
ts
.
has_background
())
{
has_style
=
true
;
auto
background
=
internal
::
make_background_color
<
Char
>
(
ts
.
get_background
());
auto
background
=
detail
::
make_background_color
<
Char
>
(
ts
.
get_background
());
buf
.
append
(
background
.
begin
(),
background
.
end
());
}
interna
l
::
vformat_to
(
buf
,
format_str
,
args
);
if
(
has_style
)
interna
l
::
reset_color
<
Char
>
(
buf
);
detai
l
::
vformat_to
(
buf
,
format_str
,
args
);
if
(
has_style
)
detai
l
::
reset_color
<
Char
>
(
buf
);
}
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
void
vprint
(
std
::
FILE
*
f
,
const
text_style
&
ts
,
const
S
&
format
,
basic_format_args
<
buffer_context
<
Char
>>
args
)
{
basic_memory_buffer
<
Char
>
buf
;
interna
l
::
vformat_to
(
buf
,
ts
,
to_string_view
(
format
),
args
);
detai
l
::
vformat_to
(
buf
,
ts
,
to_string_view
(
format
),
args
);
buf
.
push_back
(
Char
(
0
));
interna
l
::
fputs
(
buf
.
data
(),
f
);
detai
l
::
fputs
(
buf
.
data
(),
f
);
}
/**
...
...
@@ -513,10 +511,10 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
interna
l
::
is_string
<
S
>
::
value
)
>
FMT_ENABLE_IF
(
detai
l
::
is_string
<
S
>
::
value
)
>
void
print
(
std
::
FILE
*
f
,
const
text_style
&
ts
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
interna
l
::
check_format_string
<
Args
...
>
(
format_str
);
detai
l
::
check_format_string
<
Args
...
>
(
format_str
);
using
context
=
buffer_context
<
char_t
<
S
>>
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...};
vprint
(
f
,
ts
,
format_str
,
basic_format_args
<
context
>
(
as
));
...
...
@@ -530,7 +528,7 @@ void print(std::FILE* f, const text_style& ts, const S& format_str,
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
interna
l
::
is_string
<
S
>
::
value
)
>
FMT_ENABLE_IF
(
detai
l
::
is_string
<
S
>
::
value
)
>
void
print
(
const
text_style
&
ts
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
return
print
(
stdout
,
ts
,
format_str
,
args
...);
}
...
...
@@ -540,7 +538,7 @@ inline std::basic_string<Char> vformat(
const
text_style
&
ts
,
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
basic_memory_buffer
<
Char
>
buf
;
interna
l
::
vformat_to
(
buf
,
ts
,
to_string_view
(
format_str
),
args
);
detai
l
::
vformat_to
(
buf
,
ts
,
to_string_view
(
format_str
),
args
);
return
fmt
::
to_string
(
buf
);
}
...
...
@@ -560,7 +558,7 @@ template <typename S, typename... Args, typename Char = char_t<S>>
inline
std
::
basic_string
<
Char
>
format
(
const
text_style
&
ts
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
return
vformat
(
ts
,
to_string_view
(
format_str
),
interna
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
detai
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/compile.h
View file @
23c2c00d
...
...
@@ -13,7 +13,33 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace
internal
{
namespace
detail
{
// A compile-time string which is compiled into fast formatting code.
class
compiled_string
{};
template
<
typename
S
>
struct
is_compiled_string
:
std
::
is_base_of
<
compiled_string
,
S
>
{};
/**
\rst
Converts a string literal *s* into a format string that will be parsed at
compile time and converted into efficient formatting code. Requires C++17
``constexpr if`` compiler support.
**Example**::
// Converts 42 into std::string using the most efficient method and no
// runtime format string processing.
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
\endrst
*/
#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
template
<
typename
T
,
typename
...
Tail
>
const
T
&
first
(
const
T
&
value
,
const
Tail
&
...)
{
return
value
;
}
// Part of a compiled format string. It can be either literal text or a
// replacement field.
...
...
@@ -62,13 +88,15 @@ template <typename Char> struct part_counter {
if
(
begin
!=
end
)
++
num_parts
;
}
FMT_CONSTEXPR
void
on_arg_id
()
{
++
num_parts
;
}
FMT_CONSTEXPR
void
on_arg_id
(
int
)
{
++
num_parts
;
}
FMT_CONSTEXPR
void
on_arg_id
(
basic_string_view
<
Char
>
)
{
++
num_parts
;
}
FMT_CONSTEXPR
int
on_arg_id
()
{
return
++
num_parts
,
0
;
}
FMT_CONSTEXPR
int
on_arg_id
(
int
)
{
return
++
num_parts
,
0
;
}
FMT_CONSTEXPR
int
on_arg_id
(
basic_string_view
<
Char
>
)
{
return
++
num_parts
,
0
;
}
FMT_CONSTEXPR
void
on_replacement_field
(
const
Char
*
)
{}
FMT_CONSTEXPR
void
on_replacement_field
(
int
,
const
Char
*
)
{}
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
const
Char
*
begin
,
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
int
,
const
Char
*
begin
,
const
Char
*
end
)
{
// Find the matching brace.
unsigned
brace_counter
=
0
;
...
...
@@ -116,25 +144,28 @@ class format_string_compiler : public error_handler {
handler_
(
part
::
make_text
({
begin
,
to_unsigned
(
end
-
begin
)}));
}
FMT_CONSTEXPR
void
on_arg_id
()
{
FMT_CONSTEXPR
int
on_arg_id
()
{
part_
=
part
::
make_arg_index
(
parse_context_
.
next_arg_id
());
return
0
;
}
FMT_CONSTEXPR
void
on_arg_id
(
int
id
)
{
FMT_CONSTEXPR
int
on_arg_id
(
int
id
)
{
parse_context_
.
check_arg_id
(
id
);
part_
=
part
::
make_arg_index
(
id
);
return
0
;
}
FMT_CONSTEXPR
void
on_arg_id
(
basic_string_view
<
Char
>
id
)
{
FMT_CONSTEXPR
int
on_arg_id
(
basic_string_view
<
Char
>
id
)
{
part_
=
part
::
make_arg_name
(
id
);
return
0
;
}
FMT_CONSTEXPR
void
on_replacement_field
(
const
Char
*
ptr
)
{
FMT_CONSTEXPR
void
on_replacement_field
(
int
,
const
Char
*
ptr
)
{
part_
.
arg_id_end
=
ptr
;
handler_
(
part_
);
}
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
const
Char
*
begin
,
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
int
,
const
Char
*
begin
,
const
Char
*
end
)
{
auto
repl
=
typename
part
::
replacement
();
dynamic_specs_handler
<
basic_format_parse_context
<
Char
>>
handler
(
...
...
@@ -160,23 +191,24 @@ FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
format_string_compiler
<
Char
,
PartHandler
>
(
format_str
,
handler
));
}
template
<
typename
Range
,
typename
Context
,
typename
Id
>
template
<
typename
OutputIt
,
typename
Context
,
typename
Id
>
void
format_arg
(
basic_format_parse_context
<
typename
Range
::
value
_type
>&
parse_ctx
,
basic_format_parse_context
<
typename
Context
::
char
_type
>&
parse_ctx
,
Context
&
ctx
,
Id
arg_id
)
{
ctx
.
advance_to
(
visit_format_arg
(
arg_formatter
<
Range
>
(
ctx
,
&
parse_ctx
),
ctx
.
arg
(
arg_id
)));
ctx
.
advance_to
(
visit_format_arg
(
arg_formatter
<
OutputIt
,
typename
Context
::
char_type
>
(
ctx
,
&
parse_ctx
),
ctx
.
arg
(
arg_id
)));
}
// vformat_to is defined in a subnamespace to prevent ADL.
namespace
cf
{
template
<
typename
Context
,
typename
Range
,
typename
CompiledFormat
>
auto
vformat_to
(
Range
out
,
CompiledFormat
&
cf
,
basic_format_args
<
Context
>
args
)
->
typename
Context
::
iterator
{
template
<
typename
Context
,
typename
OutputIt
,
typename
CompiledFormat
>
auto
vformat_to
(
OutputIt
out
,
CompiledFormat
&
cf
,
basic_format_args
<
Context
>
args
)
->
typename
Context
::
iterator
{
using
char_type
=
typename
Context
::
char_type
;
basic_format_parse_context
<
char_type
>
parse_ctx
(
to_string_view
(
cf
.
format_str_
));
Context
ctx
(
out
.
begin
()
,
args
);
Context
ctx
(
out
,
args
);
const
auto
&
parts
=
cf
.
parts
();
for
(
auto
part_it
=
std
::
begin
(
parts
);
part_it
!=
std
::
end
(
parts
);
...
...
@@ -197,12 +229,12 @@ auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
case
format_part_t
:
:
kind
::
arg_index
:
advance_to
(
parse_ctx
,
part
.
arg_id_end
);
internal
::
format_arg
<
Range
>
(
parse_ctx
,
ctx
,
value
.
arg_index
);
detail
::
format_arg
<
OutputIt
>
(
parse_ctx
,
ctx
,
value
.
arg_index
);
break
;
case
format_part_t
:
:
kind
::
arg_name
:
advance_to
(
parse_ctx
,
part
.
arg_id_end
);
internal
::
format_arg
<
Range
>
(
parse_ctx
,
ctx
,
value
.
str
);
detail
::
format_arg
<
OutputIt
>
(
parse_ctx
,
ctx
,
value
.
str
);
break
;
case
format_part_t
:
:
kind
::
replacement
:
{
...
...
@@ -226,7 +258,9 @@ auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
advance_to
(
parse_ctx
,
part
.
arg_id_end
);
ctx
.
advance_to
(
visit_format_arg
(
arg_formatter
<
Range
>
(
ctx
,
nullptr
,
&
specs
),
arg
));
visit_format_arg
(
arg_formatter
<
OutputIt
,
typename
Context
::
char_type
>
(
ctx
,
nullptr
,
&
specs
),
arg
));
break
;
}
}
...
...
@@ -240,7 +274,7 @@ struct basic_compiled_format {};
template
<
typename
S
,
typename
=
void
>
struct
compiled_format_base
:
basic_compiled_format
{
using
char_type
=
char_t
<
S
>
;
using
parts_container
=
std
::
vector
<
interna
l
::
format_part
<
char_type
>>
;
using
parts_container
=
std
::
vector
<
detai
l
::
format_part
<
char_type
>>
;
parts_container
compiled_parts
;
...
...
@@ -305,7 +339,7 @@ struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
const
parts_container
&
parts
()
const
{
static
FMT_CONSTEXPR_DECL
const
auto
compiled_parts
=
compile_to_parts
<
char_type
,
num_format_parts
>
(
interna
l
::
to_string_view
(
S
()));
detai
l
::
to_string_view
(
S
()));
return
compiled_parts
.
data
;
}
};
...
...
@@ -318,8 +352,8 @@ class compiled_format : private compiled_format_base<S> {
private:
basic_string_view
<
char_type
>
format_str_
;
template
<
typename
Context
,
typename
Range
,
typename
CompiledFormat
>
friend
auto
cf
::
vformat_to
(
Range
out
,
CompiledFormat
&
cf
,
template
<
typename
Context
,
typename
OutputIt
,
typename
CompiledFormat
>
friend
auto
cf
::
vformat_to
(
OutputIt
out
,
CompiledFormat
&
cf
,
basic_format_args
<
Context
>
args
)
->
typename
Context
::
iterator
;
...
...
@@ -359,8 +393,7 @@ template <typename Char> struct text {
template
<
typename
OutputIt
,
typename
...
Args
>
OutputIt
format
(
OutputIt
out
,
const
Args
&
...)
const
{
// TODO: reserve
return
copy_str
<
Char
>
(
data
.
begin
(),
data
.
end
(),
out
);
return
write
<
Char
>
(
out
,
data
);
}
};
...
...
@@ -373,33 +406,6 @@ constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
return
{{
&
s
[
pos
],
size
}};
}
template
<
typename
Char
,
typename
OutputIt
,
typename
T
,
std
::
enable_if_t
<
std
::
is_integral_v
<
T
>,
int
>
=
0
>
OutputIt
format_default
(
OutputIt
out
,
T
value
)
{
// TODO: reserve
format_int
fi
(
value
);
return
std
::
copy
(
fi
.
data
(),
fi
.
data
()
+
fi
.
size
(),
out
);
}
template
<
typename
Char
,
typename
OutputIt
>
OutputIt
format_default
(
OutputIt
out
,
double
value
)
{
writer
w
(
out
);
w
.
write
(
value
);
return
w
.
out
();
}
template
<
typename
Char
,
typename
OutputIt
>
OutputIt
format_default
(
OutputIt
out
,
Char
value
)
{
*
out
++
=
value
;
return
out
;
}
template
<
typename
Char
,
typename
OutputIt
>
OutputIt
format_default
(
OutputIt
out
,
const
Char
*
value
)
{
auto
length
=
std
::
char_traits
<
Char
>::
length
(
value
);
return
copy_str
<
Char
>
(
value
,
value
+
length
,
out
);
}
// A replacement field that refers to argument N.
template
<
typename
Char
,
typename
T
,
int
N
>
struct
field
{
using
char_type
=
Char
;
...
...
@@ -408,13 +414,30 @@ template <typename Char, typename T, int N> struct field {
OutputIt
format
(
OutputIt
out
,
const
Args
&
...
args
)
const
{
// This ensures that the argument type is convertile to `const T&`.
const
T
&
arg
=
get
<
N
>
(
args
...);
return
format_default
<
Char
>
(
out
,
arg
);
return
write
<
Char
>
(
out
,
arg
);
}
};
template
<
typename
Char
,
typename
T
,
int
N
>
struct
is_compiled_format
<
field
<
Char
,
T
,
N
>>
:
std
::
true_type
{};
// A replacement field that refers to argument N and has format specifiers.
template
<
typename
Char
,
typename
T
,
int
N
>
struct
spec_field
{
using
char_type
=
Char
;
mutable
formatter
<
T
,
Char
>
fmt
;
template
<
typename
OutputIt
,
typename
...
Args
>
OutputIt
format
(
OutputIt
out
,
const
Args
&
...
args
)
const
{
// This ensures that the argument type is convertile to `const T&`.
const
T
&
arg
=
get
<
N
>
(
args
...);
basic_format_context
<
OutputIt
,
Char
>
ctx
(
out
,
{});
return
fmt
.
format
(
arg
,
ctx
);
}
};
template
<
typename
Char
,
typename
T
,
int
N
>
struct
is_compiled_format
<
spec_field
<
Char
,
T
,
N
>>
:
std
::
true_type
{};
template
<
typename
L
,
typename
R
>
struct
concat
{
L
lhs
;
R
rhs
;
...
...
@@ -450,7 +473,8 @@ constexpr auto compile_format_string(S format_str);
template
<
typename
Args
,
size_t
POS
,
int
ID
,
typename
T
,
typename
S
>
constexpr
auto
parse_tail
(
T
head
,
S
format_str
)
{
if
constexpr
(
POS
!=
to_string_view
(
format_str
).
size
())
{
if
constexpr
(
POS
!=
basic_string_view
<
typename
S
::
char_type
>
(
format_str
).
size
())
{
constexpr
auto
tail
=
compile_format_string
<
Args
,
POS
,
ID
>
(
format_str
);
if
constexpr
(
std
::
is_same
<
remove_cvref_t
<
decltype
(
tail
)
>
,
unknown_format
>
())
...
...
@@ -462,6 +486,21 @@ constexpr auto parse_tail(T head, S format_str) {
}
}
template
<
typename
T
,
typename
Char
>
struct
parse_specs_result
{
formatter
<
T
,
Char
>
fmt
;
size_t
end
;
};
template
<
typename
T
,
typename
Char
>
constexpr
parse_specs_result
<
T
,
Char
>
parse_specs
(
basic_string_view
<
Char
>
str
,
size_t
pos
)
{
str
.
remove_prefix
(
pos
);
auto
ctx
=
basic_format_parse_context
<
Char
>
(
str
);
auto
f
=
formatter
<
T
,
Char
>
();
auto
end
=
f
.
parse
(
ctx
);
return
{
f
,
pos
+
(
end
-
str
.
data
())
+
1
};
}
// Compiles a non-empty format string and returns the compiled representation
// or unknown_format() on unrecognized input.
template
<
typename
Args
,
size_t
POS
,
int
ID
,
typename
S
>
...
...
@@ -475,12 +514,13 @@ constexpr auto compile_format_string(S format_str) {
return
parse_tail
<
Args
,
POS
+
2
,
ID
>
(
make_text
(
str
,
POS
,
1
),
format_str
);
}
else
if
constexpr
(
str
[
POS
+
1
]
==
'}'
)
{
using
type
=
get_type
<
ID
,
Args
>
;
if
constexpr
(
std
::
is_same
<
type
,
int
>::
value
)
{
return
parse_tail
<
Args
,
POS
+
2
,
ID
+
1
>
(
field
<
char_type
,
type
,
ID
>
(),
format_str
);
}
else
{
return
unknown_format
();
}
return
parse_tail
<
Args
,
POS
+
2
,
ID
+
1
>
(
field
<
char_type
,
type
,
ID
>
(),
format_str
);
}
else
if
constexpr
(
str
[
POS
+
1
]
==
':'
)
{
using
type
=
get_type
<
ID
,
Args
>
;
constexpr
auto
result
=
parse_specs
<
type
>
(
str
,
POS
+
2
);
return
parse_tail
<
Args
,
result
.
end
,
ID
+
1
>
(
spec_field
<
char_type
,
type
,
ID
>
{
result
.
fmt
},
format_str
);
}
else
{
return
unknown_format
();
}
...
...
@@ -494,100 +534,130 @@ constexpr auto compile_format_string(S format_str) {
format_str
);
}
}
#endif // __cpp_if_constexpr
}
// namespace internal
#if FMT_USE_CONSTEXPR
# ifdef __cpp_if_constexpr
template
<
typename
...
Args
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
||
detail
::
is_compiled_string
<
S
>::
value
)
>
constexpr
auto
compile
(
S
format_str
)
{
constexpr
basic_string_view
<
typename
S
::
char_type
>
str
=
format_str
;
if
constexpr
(
str
.
size
()
==
0
)
{
return
interna
l
::
make_text
(
str
,
0
,
0
);
return
detai
l
::
make_text
(
str
,
0
,
0
);
}
else
{
constexpr
auto
result
=
internal
::
compile_format_string
<
interna
l
::
type_list
<
Args
...
>
,
0
,
0
>
(
detail
::
compile_format_string
<
detai
l
::
type_list
<
Args
...
>
,
0
,
0
>
(
format_str
);
if
constexpr
(
std
::
is_same
<
remove_cvref_t
<
decltype
(
result
)
>
,
interna
l
::
unknown_format
>
())
{
return
interna
l
::
compiled_format
<
S
,
Args
...
>
(
to_string_view
(
format_str
));
detai
l
::
unknown_format
>
())
{
return
detai
l
::
compiled_format
<
S
,
Args
...
>
(
to_string_view
(
format_str
));
}
else
{
return
result
;
}
}
}
#else
template
<
typename
...
Args
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
constexpr
auto
compile
(
S
format_str
)
->
detail
::
compiled_format
<
S
,
Args
...
>
{
return
detail
::
compiled_format
<
S
,
Args
...
>
(
to_string_view
(
format_str
));
}
#endif // __cpp_if_constexpr
// Compiles the format string which must be a string literal.
template
<
typename
...
Args
,
typename
Char
,
size_t
N
>
auto
compile
(
const
Char
(
&
format_str
)[
N
])
->
detail
::
compiled_format
<
const
Char
*
,
Args
...
>
{
return
detail
::
compiled_format
<
const
Char
*
,
Args
...
>
(
basic_string_view
<
Char
>
(
format_str
,
N
-
1
));
}
}
// namespace detail
// DEPRECATED! use FMT_COMPILE instead.
template
<
typename
...
Args
>
FMT_DEPRECATED
auto
compile
(
const
Args
&
...
args
)
->
decltype
(
detail
::
compile
(
args
...))
{
return
detail
::
compile
(
args
...);
}
#if FMT_USE_CONSTEXPR
# ifdef __cpp_if_constexpr
template
<
typename
CompiledFormat
,
typename
...
Args
,
typename
Char
=
typename
CompiledFormat
::
char_type
,
FMT_ENABLE_IF
(
internal
::
is_compiled_format
<
CompiledFormat
>
::
value
)
>
std
::
basic_string
<
Char
>
format
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
FMT_ENABLE_IF
(
detail
::
is_compiled_format
<
CompiledFormat
>
::
value
)
>
FMT_INLINE
std
::
basic_string
<
Char
>
format
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
cf
.
format
(
std
::
back_inserter
(
buffer
),
args
...);
detail
::
buffer
<
Char
>&
base
=
buffer
;
cf
.
format
(
std
::
back_inserter
(
base
),
args
...);
return
to_string
(
buffer
);
}
template
<
typename
OutputIt
,
typename
CompiledFormat
,
typename
...
Args
,
FMT_ENABLE_IF
(
interna
l
::
is_compiled_format
<
CompiledFormat
>
::
value
)
>
FMT_ENABLE_IF
(
detai
l
::
is_compiled_format
<
CompiledFormat
>
::
value
)
>
OutputIt
format_to
(
OutputIt
out
,
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
return
cf
.
format
(
out
,
args
...);
}
# else
template
<
typename
...
Args
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
constexpr
auto
compile
(
S
format_str
)
->
internal
::
compiled_format
<
S
,
Args
...
>
{
return
internal
::
compiled_format
<
S
,
Args
...
>
(
to_string_view
(
format_str
));
}
# endif // __cpp_if_constexpr
#endif // FMT_USE_CONSTEXPR
// Compiles the format string which must be a string literal.
template
<
typename
...
Args
,
typename
Char
,
size_t
N
>
auto
compile
(
const
Char
(
&
format_str
)[
N
])
->
internal
::
compiled_format
<
const
Char
*
,
Args
...
>
{
return
internal
::
compiled_format
<
const
Char
*
,
Args
...
>
(
basic_string_view
<
Char
>
(
format_str
,
N
-
1
));
}
template
<
typename
CompiledFormat
,
typename
...
Args
,
typename
Char
=
typename
CompiledFormat
::
char_type
,
FMT_ENABLE_IF
(
std
::
is_base_of
<
interna
l
::
basic_compiled_format
,
FMT_ENABLE_IF
(
std
::
is_base_of
<
detai
l
::
basic_compiled_format
,
CompiledFormat
>
::
value
)
>
std
::
basic_string
<
Char
>
format
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
using
range
=
buffer_range
<
Char
>
;
using
context
=
buffer_context
<
Char
>
;
internal
::
cf
::
vformat_to
<
context
>
(
range
(
buffer
),
cf
,
make_format_args
<
context
>
(
args
...));
detail
::
buffer
<
Char
>&
base
=
buffer
;
detail
::
cf
::
vformat_to
<
context
>
(
std
::
back_inserter
(
base
),
cf
,
make_format_args
<
context
>
(
args
...));
return
to_string
(
buffer
);
}
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
detail
::
is_compiled_string
<
S
>
::
value
)
>
FMT_INLINE
std
::
basic_string
<
typename
S
::
char_type
>
format
(
const
S
&
,
Args
&&
...
args
)
{
constexpr
basic_string_view
<
typename
S
::
char_type
>
str
=
S
();
if
(
str
.
size
()
==
2
&&
str
[
0
]
==
'{'
&&
str
[
1
]
==
'}'
)
return
fmt
::
to_string
(
detail
::
first
(
args
...));
constexpr
auto
compiled
=
detail
::
compile
<
Args
...
>
(
S
());
return
format
(
compiled
,
std
::
forward
<
Args
>
(
args
)...);
}
template
<
typename
OutputIt
,
typename
CompiledFormat
,
typename
...
Args
,
FMT_ENABLE_IF
(
std
::
is_base_of
<
interna
l
::
basic_compiled_format
,
FMT_ENABLE_IF
(
std
::
is_base_of
<
detai
l
::
basic_compiled_format
,
CompiledFormat
>
::
value
)
>
OutputIt
format_to
(
OutputIt
out
,
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
using
char_type
=
typename
CompiledFormat
::
char_type
;
using
range
=
internal
::
output_range
<
OutputIt
,
char_type
>
;
using
context
=
format_context_t
<
OutputIt
,
char_type
>
;
return
internal
::
cf
::
vformat_to
<
context
>
(
range
(
out
)
,
cf
,
make_format_args
<
context
>
(
args
...));
return
detail
::
cf
::
vformat_to
<
context
>
(
out
,
cf
,
make_format_args
<
context
>
(
args
...));
}
template
<
typename
OutputIt
,
typename
CompiledFormat
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_output_iterator
<
OutputIt
>
::
value
)
>
template
<
typename
OutputIt
,
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
detail
::
is_compiled_string
<
S
>
::
value
)
>
OutputIt
format_to
(
OutputIt
out
,
const
S
&
,
const
Args
&
...
args
)
{
constexpr
auto
compiled
=
detail
::
compile
<
Args
...
>
(
S
());
return
format_to
(
out
,
compiled
,
args
...);
}
template
<
typename
OutputIt
,
typename
CompiledFormat
,
typename
...
Args
,
FMT_ENABLE_IF
(
detail
::
is_output_iterator
<
OutputIt
>
::
value
&&
std
::
is_base_of
<
detail
::
basic_compiled_format
,
CompiledFormat
>::
value
)
>
format_to_n_result
<
OutputIt
>
format_to_n
(
OutputIt
out
,
size_t
n
,
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
auto
it
=
format_to
(
interna
l
::
truncating_iterator
<
OutputIt
>
(
out
,
n
),
cf
,
args
...);
format_to
(
detai
l
::
truncating_iterator
<
OutputIt
>
(
out
,
n
),
cf
,
args
...);
return
{
it
.
base
(),
it
.
count
()};
}
template
<
typename
CompiledFormat
,
typename
...
Args
>
s
td
::
s
ize_t
formatted_size
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
return
format_to
(
interna
l
::
counting_iterator
(),
cf
,
args
...).
count
();
size_t
formatted_size
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
return
format_to
(
detai
l
::
counting_iterator
(),
cf
,
args
...).
count
();
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/core.h
View file @
23c2c00d
...
...
@@ -18,32 +18,7 @@
#include <vector>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 60201
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
#else
# define FMT_HAS_FEATURE(x) 0
#endif
#if defined(__has_include) && !defined(__INTELLISENSE__) && \
!(defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1600)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
#endif
#ifdef __has_cpp_attribute
# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
(__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
(__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
#define FMT_VERSION 70003
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
...
...
@@ -57,6 +32,12 @@
# define FMT_GCC_VERSION 0
#endif
#if defined(__INTEL_COMPILER)
# define FMT_ICC_VERSION __INTEL_COMPILER
#else
# define FMT_ICC_VERSION 0
#endif
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
#else
...
...
@@ -71,17 +52,43 @@
#ifdef _MSC_VER
# define FMT_MSC_VER _MSC_VER
# define FMT_SUPPRESS_MSC_WARNING(n) __pragma(warning(suppress : n))
#else
# define FMT_MSC_VER 0
# define FMT_SUPPRESS_MSC_WARNING(n)
#endif
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
#else
# define FMT_HAS_FEATURE(x) 0
#endif
#if defined(__has_include) && !defined(__INTELLISENSE__) && \
!(FMT_ICC_VERSION && FMT_ICC_VERSION < 1600)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
#endif
#ifdef __has_cpp_attribute
# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
(__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
(__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
// Check if relaxed C++14 constexpr is supported.
// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
#ifndef FMT_USE_CONSTEXPR
# define FMT_USE_CONSTEXPR \
(FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
(FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
!FMT_NVCC
!FMT_NVCC
&& !FMT_ICC_VERSION
#endif
#if FMT_USE_CONSTEXPR
# define FMT_CONSTEXPR constexpr
...
...
@@ -141,14 +148,6 @@
# define FMT_NORETURN
#endif
#ifndef FMT_MAYBE_UNUSED
# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
# define FMT_MAYBE_UNUSED [[maybe_unused]]
# else
# define FMT_MAYBE_UNUSED
# endif
#endif
#ifndef FMT_DEPRECATED
# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
# define FMT_DEPRECATED [[deprecated]]
...
...
@@ -164,12 +163,20 @@
#endif
// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
#if
defined(__INTEL_COMPILER)
|| defined(__PGI) || FMT_NVCC
#if
FMT_ICC_VERSION
|| defined(__PGI) || FMT_NVCC
# define FMT_DEPRECATED_ALIAS
#else
# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
#endif
#ifndef FMT_INLINE
# if FMT_GCC_VERSION || FMT_CLANG_VERSION
# define FMT_INLINE inline __attribute__((always_inline))
# else
# define FMT_INLINE inline
# endif
#endif
#ifndef FMT_BEGIN_NAMESPACE
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
FMT_MSC_VER >= 1900
...
...
@@ -181,39 +188,29 @@
# define FMT_INLINE_NAMESPACE namespace
# define FMT_END_NAMESPACE \
} \
using namespace v
6
; \
using namespace v
7
; \
}
# endif
# define FMT_BEGIN_NAMESPACE \
namespace fmt { \
FMT_INLINE_NAMESPACE v
6
{
FMT_INLINE_NAMESPACE v
7
{
#endif
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
# if FMT_MSC_VER
# define FMT_NO_W4275 __pragma(warning(suppress : 4275))
# else
# define FMT_NO_W4275
# endif
# define FMT_CLASS_API FMT_NO_W4275
# define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275)
# ifdef FMT_EXPORT
# define FMT_API __declspec(dllexport)
# define FMT_EXTERN_TEMPLATE_API FMT_API
# define FMT_EXPORTED
# elif defined(FMT_SHARED)
# define FMT_API __declspec(dllimport)
# define FMT_EXTERN_TEMPLATE_API FMT_API
# endif
#endif
#ifndef FMT_CLASS_API
#else
# define FMT_CLASS_API
#endif
#ifndef FMT_API
# if FMT_GCC_VERSION || FMT_CLANG_VERSION
# define FMT_API __attribute__((visibility("default")))
# define FMT_EXTERN_TEMPLATE_API FMT_API
# define FMT_INSTANTIATION_DEF_API
# else
# define FMT_API
# endif
# define FMT_API
#endif
#ifndef FMT_EXTERN_TEMPLATE_API
# define FMT_EXTERN_TEMPLATE_API
...
...
@@ -270,14 +267,11 @@ struct monostate {};
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
namespace
interna
l
{
namespace
detai
l
{
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
template
<
typename
T
>
FMT_CONSTEXPR
T
const_check
(
T
value
)
{
return
value
;
}
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
template
<
typename
...
Ts
>
struct
void_t_impl
{
using
type
=
void
;
};
template
<
typename
T
>
constexpr
T
const_check
(
T
value
)
{
return
value
;
}
FMT_NORETURN
FMT_API
void
assert_fail
(
const
char
*
file
,
int
line
,
const
char
*
message
);
...
...
@@ -290,7 +284,7 @@ FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
# define FMT_ASSERT(condition, message) \
((condition)
/* void() fails with -Winvalid-constexpr on clang 4.0.1 */
\
? (void)0 \
: ::fmt::
interna
l::assert_fail(__FILE__, __LINE__, (message)))
: ::fmt::
detai
l::assert_fail(__FILE__, __LINE__, (message)))
# endif
#endif
...
...
@@ -305,7 +299,7 @@ template <typename T> struct std_string_view {};
#ifdef FMT_USE_INT128
// Do nothing.
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
&& !(FMT_CLANG_VERSION && FMT_MSC_VER)
# define FMT_USE_INT128 1
using
int128_t
=
__int128_t
;
using
uint128_t
=
__uint128_t
;
...
...
@@ -324,7 +318,7 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
return
static_cast
<
typename
std
::
make_unsigned
<
Int
>::
type
>
(
value
);
}
constexpr
unsigned
char
micro
[]
=
"\u00B5"
;
FMT_SUPPRESS_MSC_WARNING
(
4566
)
constexpr
unsigned
char
micro
[]
=
"\u00B5"
;
template
<
typename
Char
>
constexpr
bool
is_unicode
()
{
return
FMT_UNICODE
||
sizeof
(
Char
)
!=
1
||
...
...
@@ -336,10 +330,11 @@ using char8_type = char8_t;
#else
enum
char8_type
:
unsigned
char
{};
#endif
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
...
Ts
>
using
void_t
=
typename
internal
::
void_t_impl
<
Ts
...
>::
type
;
#ifdef FMT_USE_INTERNAL
namespace
internal
=
detail
;
// DEPRECATED
#endif
/**
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
...
...
@@ -354,14 +349,13 @@ template <typename Char> class basic_string_view {
size_t
size_
;
public:
using
char_type
FMT_DEPRECATED_ALIAS
=
Char
;
using
value_type
=
Char
;
using
iterator
=
const
Char
*
;
FMT_CONSTEXPR
basic_string_view
()
FMT_NOEXCEPT
:
data_
(
nullptr
),
size_
(
0
)
{}
constexpr
basic_string_view
()
FMT_NOEXCEPT
:
data_
(
nullptr
),
size_
(
0
)
{}
/** Constructs a string reference object from a C string and a size. */
FMT_CONSTEXPR
basic_string_view
(
const
Char
*
s
,
size_t
count
)
FMT_NOEXCEPT
constexpr
basic_string_view
(
const
Char
*
s
,
size_t
count
)
FMT_NOEXCEPT
:
data_
(
s
),
size_
(
count
)
{}
...
...
@@ -384,22 +378,21 @@ template <typename Char> class basic_string_view {
:
data_
(
s
.
data
()),
size_
(
s
.
size
())
{}
template
<
typename
S
,
FMT_ENABLE_IF
(
std
::
is_same
<
S
,
internal
::
std_string_view
<
Char
>
>::
value
)
>
template
<
typename
S
,
FMT_ENABLE_IF
(
std
::
is_same
<
S
,
detail
::
std_string_view
<
Char
>
>::
value
)
>
FMT_CONSTEXPR
basic_string_view
(
S
s
)
FMT_NOEXCEPT
:
data_
(
s
.
data
()),
size_
(
s
.
size
())
{}
/** Returns a pointer to the string data. */
FMT_CONSTEXPR
const
Char
*
data
()
const
{
return
data_
;
}
constexpr
const
Char
*
data
()
const
{
return
data_
;
}
/** Returns the string size. */
FMT_CONSTEXPR
size_t
size
()
const
{
return
size_
;
}
constexpr
size_t
size
()
const
{
return
size_
;
}
FMT_CONSTEXPR
iterator
begin
()
const
{
return
data_
;
}
FMT_CONSTEXPR
iterator
end
()
const
{
return
data_
+
size_
;
}
constexpr
iterator
begin
()
const
{
return
data_
;
}
constexpr
iterator
end
()
const
{
return
data_
+
size_
;
}
FMT_CONSTEXPR
const
Char
&
operator
[](
size_t
pos
)
const
{
return
data_
[
pos
];
}
constexpr
const
Char
&
operator
[](
size_t
pos
)
const
{
return
data_
[
pos
];
}
FMT_CONSTEXPR
void
remove_prefix
(
size_t
n
)
{
data_
+=
n
;
...
...
@@ -438,16 +431,11 @@ template <typename Char> class basic_string_view {
using
string_view
=
basic_string_view
<
char
>
;
using
wstring_view
=
basic_string_view
<
wchar_t
>
;
#ifndef __cpp_char8_t
// char8_t is deprecated; use char instead.
using
char8_t
FMT_DEPRECATED_ALIAS
=
internal
::
char8_type
;
#endif
/** Specifies if ``T`` is a character type. Can be specialized by users. */
template
<
typename
T
>
struct
is_char
:
std
::
false_type
{};
template
<
>
struct
is_char
<
char
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
wchar_t
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
interna
l
::
char8_type
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
detai
l
::
char8_type
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
char16_t
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
char32_t
>
:
std
::
true_type
{};
...
...
@@ -484,14 +472,13 @@ inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
}
template
<
typename
Char
,
FMT_ENABLE_IF
(
!
std
::
is_empty
<
internal
::
std_string_view
<
Char
>
>::
value
)
>
inline
basic_string_view
<
Char
>
to_string_view
(
internal
::
std_string_view
<
Char
>
s
)
{
FMT_ENABLE_IF
(
!
std
::
is_empty
<
detail
::
std_string_view
<
Char
>
>::
value
)
>
inline
basic_string_view
<
Char
>
to_string_view
(
detail
::
std_string_view
<
Char
>
s
)
{
return
s
;
}
// A base class for compile-time strings. It is defined in the fmt namespace to
// make formatting functions visible via ADL, e.g. format(
fmt
("{}"), 42).
// make formatting functions visible via ADL, e.g. format(
FMT_STRING
("{}"), 42).
struct
compile_string
{};
template
<
typename
S
>
...
...
@@ -502,9 +489,9 @@ constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
return
s
;
}
namespace
interna
l
{
namespace
detai
l
{
void
to_string_view
(...);
using
fmt
::
v
6
::
to_string_view
;
using
fmt
::
v
7
::
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
...
...
@@ -520,16 +507,16 @@ template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
};
struct
error_handler
{
FMT_CONSTEXPR
error_handler
()
=
default
;
FMT_CONSTEXPR
error_handler
(
const
error_handler
&
)
=
default
;
constexpr
error_handler
()
=
default
;
constexpr
error_handler
(
const
error_handler
&
)
=
default
;
// This function is intentionally not constexpr to give a compile-time error.
FMT_NORETURN
FMT_API
void
on_error
(
const
char
*
message
);
};
}
// namespace
interna
l
}
// namespace
detai
l
/** String's character type. */
template
<
typename
S
>
using
char_t
=
typename
interna
l
::
char_t_impl
<
S
>::
type
;
template
<
typename
S
>
using
char_t
=
typename
detai
l
::
char_t_impl
<
S
>::
type
;
/**
\rst
...
...
@@ -547,7 +534,7 @@ template <typename S> using char_t = typename internal::char_t_impl<S>::type;
+-----------------------+-------------------------------------+
\endrst
*/
template
<
typename
Char
,
typename
ErrorHandler
=
interna
l
::
error_handler
>
template
<
typename
Char
,
typename
ErrorHandler
=
detai
l
::
error_handler
>
class
basic_format_parse_context
:
private
ErrorHandler
{
private:
basic_string_view
<
Char
>
format_str_
;
...
...
@@ -557,26 +544,24 @@ class basic_format_parse_context : private ErrorHandler {
using
char_type
=
Char
;
using
iterator
=
typename
basic_string_view
<
Char
>::
iterator
;
explicit
FMT_CONSTEXPR
basic_format_parse_context
(
basic_string_view
<
Char
>
format_str
,
ErrorHandler
eh
=
ErrorHandler
()
)
explicit
constexpr
basic_format_parse_context
(
basic_string_view
<
Char
>
format_str
,
ErrorHandler
eh
=
{}
)
:
ErrorHandler
(
eh
),
format_str_
(
format_str
),
next_arg_id_
(
0
)
{}
/**
Returns an iterator to the beginning of the format string range being
parsed.
*/
FMT_CONSTEXPR
iterator
begin
()
const
FMT_NOEXCEPT
{
return
format_str_
.
begin
();
}
constexpr
iterator
begin
()
const
FMT_NOEXCEPT
{
return
format_str_
.
begin
();
}
/**
Returns an iterator past the end of the format string range being parsed.
*/
FMT_CONSTEXPR
iterator
end
()
const
FMT_NOEXCEPT
{
return
format_str_
.
end
();
}
constexpr
iterator
end
()
const
FMT_NOEXCEPT
{
return
format_str_
.
end
();
}
/** Advances the begin iterator to ``it``. */
FMT_CONSTEXPR
void
advance_to
(
iterator
it
)
{
format_str_
.
remove_prefix
(
interna
l
::
to_unsigned
(
it
-
begin
()));
format_str_
.
remove_prefix
(
detai
l
::
to_unsigned
(
it
-
begin
()));
}
/**
...
...
@@ -584,6 +569,8 @@ class basic_format_parse_context : private ErrorHandler {
the next argument index and switches to the automatic indexing.
*/
FMT_CONSTEXPR
int
next_arg_id
()
{
// Don't check if the argument id is valid to avoid overhead and because it
// will be checked during formatting anyway.
if
(
next_arg_id_
>=
0
)
return
next_arg_id_
++
;
on_error
(
"cannot switch from manual to automatic argument indexing"
);
return
0
;
...
...
@@ -606,20 +593,15 @@ class basic_format_parse_context : private ErrorHandler {
ErrorHandler
::
on_error
(
message
);
}
FMT_CONSTEXPR
ErrorHandler
error_handler
()
const
{
return
*
this
;
}
constexpr
ErrorHandler
error_handler
()
const
{
return
*
this
;
}
};
using
format_parse_context
=
basic_format_parse_context
<
char
>
;
using
wformat_parse_context
=
basic_format_parse_context
<
wchar_t
>
;
template
<
typename
Char
,
typename
ErrorHandler
=
internal
::
error_handler
>
using
basic_parse_context
FMT_DEPRECATED_ALIAS
=
basic_format_parse_context
<
Char
,
ErrorHandler
>
;
using
parse_context
FMT_DEPRECATED_ALIAS
=
basic_format_parse_context
<
char
>
;
using
wparse_context
FMT_DEPRECATED_ALIAS
=
basic_format_parse_context
<
wchar_t
>
;
template
<
typename
Context
>
class
basic_format_arg
;
template
<
typename
Context
>
class
basic_format_args
;
template
<
typename
Context
>
class
dynamic_format_arg_store
;
// A formatter for objects of type T.
template
<
typename
T
,
typename
Char
=
char
,
typename
Enable
=
void
>
...
...
@@ -628,43 +610,44 @@ struct formatter {
formatter
()
=
delete
;
};
template
<
typename
T
,
typename
Char
,
typename
Enable
=
void
>
struct
FMT_DEPRECATED
convert_to_int
:
bool_constant
<!
std
::
is_arithmetic
<
T
>::
value
&&
std
::
is_convertible
<
T
,
int
>::
value
>
{};
// 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
<
typename
T
,
typename
Context
>
using
has_formatter
=
std
::
is_constructible
<
typename
Context
::
template
formatter_type
<
T
>
>
;
namespace
interna
l
{
namespace
detai
l
{
/** A contiguous memory buffer with an optional growing ability. */
/**
\rst
A contiguous memory buffer with an optional growing ability. It is an internal
class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`.
\endrst
*/
template
<
typename
T
>
class
buffer
{
private:
T
*
ptr_
;
s
td
::
s
ize_t
size_
;
s
td
::
s
ize_t
capacity_
;
size_t
size_
;
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
)
{}
FMT_SUPPRESS_MSC_WARNING
(
26495
)
buffer
(
size_t
sz
)
FMT_NOEXCEPT
:
size_
(
sz
),
capacity_
(
sz
)
{}
buffer
(
T
*
p
=
nullptr
,
s
td
::
size_t
sz
=
0
,
std
::
size_t
cap
=
0
)
FMT_NOEXCEPT
buffer
(
T
*
p
=
nullptr
,
s
ize_t
sz
=
0
,
size_t
cap
=
0
)
FMT_NOEXCEPT
:
ptr_
(
p
),
size_
(
sz
),
capacity_
(
cap
)
{}
/** Sets the buffer data and capacity. */
void
set
(
T
*
buf_data
,
s
td
::
s
ize_t
buf_capacity
)
FMT_NOEXCEPT
{
void
set
(
T
*
buf_data
,
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
(
s
td
::
s
ize_t
capacity
)
=
0
;
virtual
void
grow
(
size_t
capacity
)
=
0
;
public:
using
value_type
=
T
;
...
...
@@ -681,10 +664,10 @@ template <typename T> class buffer {
const
T
*
end
()
const
FMT_NOEXCEPT
{
return
ptr_
+
size_
;
}
/** Returns the size of this buffer. */
s
td
::
s
ize_t
size
()
const
FMT_NOEXCEPT
{
return
size_
;
}
size_t
size
()
const
FMT_NOEXCEPT
{
return
size_
;
}
/** Returns the capacity of this buffer. */
s
td
::
s
ize_t
capacity
()
const
FMT_NOEXCEPT
{
return
capacity_
;
}
size_t
capacity
()
const
FMT_NOEXCEPT
{
return
capacity_
;
}
/** Returns a pointer to the buffer data. */
T
*
data
()
FMT_NOEXCEPT
{
return
ptr_
;
}
...
...
@@ -695,7 +678,7 @@ template <typename T> class buffer {
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void
resize
(
s
td
::
s
ize_t
new_size
)
{
void
resize
(
size_t
new_size
)
{
reserve
(
new_size
);
size_
=
new_size
;
}
...
...
@@ -704,7 +687,7 @@ template <typename T> class buffer {
void
clear
()
{
size_
=
0
;
}
/** Reserves space to store at least *capacity* elements. */
void
reserve
(
s
td
::
s
ize_t
new_capacity
)
{
void
reserve
(
size_t
new_capacity
)
{
if
(
new_capacity
>
capacity_
)
grow
(
new_capacity
);
}
...
...
@@ -729,7 +712,7 @@ class container_buffer : public buffer<typename Container::value_type> {
Container
&
container_
;
protected:
void
grow
(
s
td
::
s
ize_t
capacity
)
FMT_OVERRIDE
{
void
grow
(
size_t
capacity
)
FMT_OVERRIDE
{
container_
.
resize
(
capacity
);
this
->
set
(
&
container_
[
0
],
capacity
);
}
...
...
@@ -760,12 +743,78 @@ template <typename T, typename Context>
using
has_fallback_formatter
=
std
::
is_constructible
<
fallback_formatter
<
T
,
typename
Context
::
char_type
>>
;
template
<
typename
Char
>
struct
named_arg_base
;
template
<
typename
T
,
typename
Char
>
struct
named_arg
;
struct
view
{};
template
<
typename
Char
,
typename
T
>
struct
named_arg
:
view
{
const
Char
*
name
;
const
T
&
value
;
named_arg
(
const
Char
*
n
,
const
T
&
v
)
:
name
(
n
),
value
(
v
)
{}
};
template
<
typename
Char
>
struct
named_arg_info
{
const
Char
*
name
;
int
id
;
};
template
<
typename
T
,
typename
Char
,
size_t
NUM_ARGS
,
size_t
NUM_NAMED_ARGS
>
struct
arg_data
{
// args_[0].named_args points to named_args_ to avoid bloating format_args.
T
args_
[
1
+
(
NUM_ARGS
!=
0
?
NUM_ARGS
:
1
)];
named_arg_info
<
Char
>
named_args_
[
NUM_NAMED_ARGS
];
template
<
typename
...
U
>
arg_data
(
const
U
&
...
init
)
:
args_
{
T
(
named_args_
,
NUM_NAMED_ARGS
),
init
...}
{}
arg_data
(
const
arg_data
&
other
)
=
delete
;
const
T
*
args
()
const
{
return
args_
+
1
;
}
named_arg_info
<
Char
>*
named_args
()
{
return
named_args_
;
}
};
template
<
typename
T
,
typename
Char
,
size_t
NUM_ARGS
>
struct
arg_data
<
T
,
Char
,
NUM_ARGS
,
0
>
{
T
args_
[
NUM_ARGS
!=
0
?
NUM_ARGS
:
1
];
template
<
typename
...
U
>
FMT_INLINE
arg_data
(
const
U
&
...
init
)
:
args_
{
init
...}
{}
FMT_INLINE
const
T
*
args
()
const
{
return
args_
;
}
FMT_INLINE
std
::
nullptr_t
named_args
()
{
return
nullptr
;
}
};
template
<
typename
Char
>
inline
void
init_named_args
(
named_arg_info
<
Char
>*
,
int
,
int
)
{}
template
<
typename
Char
,
typename
T
,
typename
...
Tail
>
void
init_named_args
(
named_arg_info
<
Char
>*
named_args
,
int
arg_count
,
int
named_arg_count
,
const
T
&
,
const
Tail
&
...
args
)
{
init_named_args
(
named_args
,
arg_count
+
1
,
named_arg_count
,
args
...);
}
template
<
typename
Char
,
typename
T
,
typename
...
Tail
>
void
init_named_args
(
named_arg_info
<
Char
>*
named_args
,
int
arg_count
,
int
named_arg_count
,
const
named_arg
<
Char
,
T
>&
arg
,
const
Tail
&
...
args
)
{
named_args
[
named_arg_count
++
]
=
{
arg
.
name
,
arg_count
};
init_named_args
(
named_args
,
arg_count
+
1
,
named_arg_count
,
args
...);
}
template
<
typename
...
Args
>
FMT_INLINE
void
init_named_args
(
std
::
nullptr_t
,
int
,
int
,
const
Args
&
...)
{}
template
<
typename
T
>
struct
is_named_arg
:
std
::
false_type
{};
template
<
typename
T
,
typename
Char
>
struct
is_named_arg
<
named_arg
<
Char
,
T
>>
:
std
::
true_type
{};
template
<
bool
B
=
false
>
constexpr
size_t
count
()
{
return
B
?
1
:
0
;
}
template
<
bool
B1
,
bool
B2
,
bool
...
Tail
>
constexpr
size_t
count
()
{
return
(
B1
?
1
:
0
)
+
count
<
B2
,
Tail
...
>
();
}
template
<
typename
...
Args
>
constexpr
size_t
count_named_args
()
{
return
count
<
is_named_arg
<
Args
>::
value
...
>
();
}
enum
class
type
{
none_type
,
named_arg_type
,
// Integer types should go first,
int_type
,
uint_type
,
...
...
@@ -796,7 +845,6 @@ struct type_constant : std::integral_constant<type, type::custom_type> {};
struct type_constant<Type, Char> \
: std::integral_constant<type, type::constant> {}
FMT_TYPE_CONSTANT
(
const
named_arg_base
<
Char
>&
,
named_arg_type
);
FMT_TYPE_CONSTANT
(
int
,
int_type
);
FMT_TYPE_CONSTANT
(
unsigned
,
uint_type
);
FMT_TYPE_CONSTANT
(
long
long
,
long_long_type
);
...
...
@@ -812,26 +860,28 @@ FMT_TYPE_CONSTANT(const Char*, cstring_type);
FMT_TYPE_CONSTANT
(
basic_string_view
<
Char
>
,
string_type
);
FMT_TYPE_CONSTANT
(
const
void
*
,
pointer_type
);
FMT_CONSTEXPR
bool
is_integral_type
(
type
t
)
{
FMT_ASSERT
(
t
!=
type
::
named_arg_type
,
"invalid argument type"
);
constexpr
bool
is_integral_type
(
type
t
)
{
return
t
>
type
::
none_type
&&
t
<=
type
::
last_integer_type
;
}
FMT_CONSTEXPR
bool
is_arithmetic_type
(
type
t
)
{
FMT_ASSERT
(
t
!=
type
::
named_arg_type
,
"invalid argument type"
);
constexpr
bool
is_arithmetic_type
(
type
t
)
{
return
t
>
type
::
none_type
&&
t
<=
type
::
last_numeric_type
;
}
template
<
typename
Char
>
struct
string_value
{
const
Char
*
data
;
std
::
size_t
size
;
size_t
size
;
};
template
<
typename
Char
>
struct
named_arg_value
{
const
named_arg_info
<
Char
>*
data
;
size_t
size
;
};
template
<
typename
Context
>
struct
custom_value
{
using
parse_context
=
basic_format_parse_context
<
typename
Context
::
char_type
>
;
using
parse_context
=
typename
Context
::
parse_context_type
;
const
void
*
value
;
void
(
*
format
)(
const
void
*
arg
,
typename
Context
::
parse_context_type
&
parse_ctx
,
Context
&
ctx
);
void
(
*
format
)(
const
void
*
arg
,
parse_context
&
parse_ctx
,
Context
&
ctx
);
};
// A formatting argument value.
...
...
@@ -854,28 +904,30 @@ template <typename Context> class value {
const
void
*
pointer
;
string_value
<
char_type
>
string
;
custom_value
<
Context
>
custom
;
const
named_arg_base
<
char_type
>*
named_arg
;
named_arg_value
<
char_type
>
named_args
;
};
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
(
int128_t
val
)
:
int128_value
(
val
)
{}
value
(
uint128_t
val
)
:
uint128_value
(
val
)
{}
value
(
float
val
)
:
float_value
(
val
)
{}
value
(
double
val
)
:
double_value
(
val
)
{}
value
(
long
double
val
)
:
long_double_value
(
val
)
{}
value
(
bool
val
)
:
bool_value
(
val
)
{}
value
(
char_type
val
)
:
char_value
(
val
)
{}
value
(
const
char_type
*
val
)
{
string
.
data
=
val
;
}
value
(
basic_string_view
<
char_type
>
val
)
{
constexpr
FMT_INLINE
value
(
int
val
=
0
)
:
int_value
(
val
)
{}
constexpr
FMT_INLINE
value
(
unsigned
val
)
:
uint_value
(
val
)
{}
FMT_INLINE
value
(
long
long
val
)
:
long_long_value
(
val
)
{}
FMT_INLINE
value
(
unsigned
long
long
val
)
:
ulong_long_value
(
val
)
{}
FMT_INLINE
value
(
int128_t
val
)
:
int128_value
(
val
)
{}
FMT_INLINE
value
(
uint128_t
val
)
:
uint128_value
(
val
)
{}
FMT_INLINE
value
(
float
val
)
:
float_value
(
val
)
{}
FMT_INLINE
value
(
double
val
)
:
double_value
(
val
)
{}
FMT_INLINE
value
(
long
double
val
)
:
long_double_value
(
val
)
{}
FMT_INLINE
value
(
bool
val
)
:
bool_value
(
val
)
{}
FMT_INLINE
value
(
char_type
val
)
:
char_value
(
val
)
{}
FMT_INLINE
value
(
const
char_type
*
val
)
{
string
.
data
=
val
;
}
FMT_INLINE
value
(
basic_string_view
<
char_type
>
val
)
{
string
.
data
=
val
.
data
();
string
.
size
=
val
.
size
();
}
value
(
const
void
*
val
)
:
pointer
(
val
)
{}
FMT_INLINE
value
(
const
void
*
val
)
:
pointer
(
val
)
{}
FMT_INLINE
value
(
const
named_arg_info
<
char_type
>*
args
,
size_t
size
)
:
named_args
{
args
,
size
}
{}
template
<
typename
T
>
value
(
const
T
&
val
)
{
template
<
typename
T
>
FMT_INLINE
value
(
const
T
&
val
)
{
custom
.
value
=
&
val
;
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
...
...
@@ -886,8 +938,6 @@ template <typename Context> class value {
fallback_formatter
<
T
,
char_type
>>>
;
}
value
(
const
named_arg_base
<
char_type
>&
val
)
{
named_arg
=
&
val
;
}
private:
// Formats an argument of a custom type, such as a user-defined class.
template
<
typename
T
,
typename
Formatter
>
...
...
@@ -973,6 +1023,14 @@ template <typename Context> struct arg_mapper {
static_assert
(
std
::
is_same
<
char_type
,
char
>::
value
,
"invalid string type"
);
return
reinterpret_cast
<
const
char
*>
(
val
);
}
FMT_CONSTEXPR
const
char
*
map
(
signed
char
*
val
)
{
const
auto
*
const_val
=
val
;
return
map
(
const_val
);
}
FMT_CONSTEXPR
const
char
*
map
(
unsigned
char
*
val
)
{
const
auto
*
const_val
=
val
;
return
map
(
const_val
);
}
FMT_CONSTEXPR
const
void
*
map
(
void
*
val
)
{
return
val
;
}
FMT_CONSTEXPR
const
void
*
map
(
const
void
*
val
)
{
return
val
;
}
...
...
@@ -1004,11 +1062,9 @@ template <typename Context> struct arg_mapper {
}
template
<
typename
T
>
FMT_CONSTEXPR
const
named_arg_base
<
char_type
>&
map
(
const
named_arg
<
T
,
char_type
>&
val
)
{
auto
arg
=
make_arg
<
Context
>
(
val
.
value
);
std
::
memcpy
(
val
.
data
,
&
arg
,
sizeof
(
arg
));
return
val
;
FMT_CONSTEXPR
auto
map
(
const
named_arg
<
char_type
,
T
>&
val
)
->
decltype
(
std
::
declval
<
arg_mapper
>
().
map
(
val
.
value
))
{
return
map
(
val
.
value
);
}
int
map
(...)
{
...
...
@@ -1028,23 +1084,22 @@ using mapped_type_constant =
type_constant
<
decltype
(
arg_mapper
<
Context
>
().
map
(
std
::
declval
<
const
T
&>
())),
typename
Context
::
char_type
>
;
enum
{
packed_arg_bits
=
5
};
enum
{
packed_arg_bits
=
4
};
// Maximum number of arguments with packed types.
enum
{
max_packed_args
=
6
3
/
packed_arg_bits
};
enum
{
max_packed_args
=
6
2
/
packed_arg_bits
};
enum
:
unsigned
long
long
{
is_unpacked_bit
=
1ULL
<<
63
};
template
<
typename
Context
>
class
arg_map
;
}
// namespace internal
enum
:
unsigned
long
long
{
has_named_args_bit
=
1ULL
<<
62
};
}
// namespace detail
// A formatting argument. It is a trivially copyable/constructible type to
// allow storage in basic_memory_buffer.
template
<
typename
Context
>
class
basic_format_arg
{
private:
interna
l
::
value
<
Context
>
value_
;
interna
l
::
type
type_
;
detai
l
::
value
<
Context
>
value_
;
detai
l
::
type
type_
;
template
<
typename
ContextType
,
typename
T
>
friend
FMT_CONSTEXPR
basic_format_arg
<
ContextType
>
interna
l
::
make_arg
(
friend
FMT_CONSTEXPR
basic_format_arg
<
ContextType
>
detai
l
::
make_arg
(
const
T
&
value
);
template
<
typename
Visitor
,
typename
Ctx
>
...
...
@@ -1053,14 +1108,20 @@ template <typename Context> class basic_format_arg {
->
decltype
(
vis
(
0
));
friend
class
basic_format_args
<
Context
>
;
friend
class
internal
::
arg_map
<
Context
>
;
friend
class
dynamic_format_arg_store
<
Context
>
;
using
char_type
=
typename
Context
::
char_type
;
template
<
typename
T
,
typename
Char
,
size_t
NUM_ARGS
,
size_t
NUM_NAMED_ARGS
>
friend
struct
detail
::
arg_data
;
basic_format_arg
(
const
detail
::
named_arg_info
<
char_type
>*
args
,
size_t
size
)
:
value_
(
args
,
size
)
{}
public:
class
handle
{
public:
explicit
handle
(
interna
l
::
custom_value
<
Context
>
custom
)
:
custom_
(
custom
)
{}
explicit
handle
(
detai
l
::
custom_value
<
Context
>
custom
)
:
custom_
(
custom
)
{}
void
format
(
typename
Context
::
parse_context_type
&
parse_ctx
,
Context
&
ctx
)
const
{
...
...
@@ -1068,19 +1129,19 @@ template <typename Context> class basic_format_arg {
}
private:
interna
l
::
custom_value
<
Context
>
custom_
;
detai
l
::
custom_value
<
Context
>
custom_
;
};
FMT_CONSTEXPR
basic_format_arg
()
:
type_
(
interna
l
::
type
::
none_type
)
{}
constexpr
basic_format_arg
()
:
type_
(
detai
l
::
type
::
none_type
)
{}
FMT_CONSTEXPR
explicit
operator
bool
()
const
FMT_NOEXCEPT
{
return
type_
!=
interna
l
::
type
::
none_type
;
constexpr
explicit
operator
bool
()
const
FMT_NOEXCEPT
{
return
type_
!=
detai
l
::
type
::
none_type
;
}
interna
l
::
type
type
()
const
{
return
type_
;
}
detai
l
::
type
type
()
const
{
return
type_
;
}
bool
is_integral
()
const
{
return
interna
l
::
is_integral_type
(
type_
);
}
bool
is_arithmetic
()
const
{
return
interna
l
::
is_arithmetic_type
(
type_
);
}
bool
is_integral
()
const
{
return
detai
l
::
is_integral_type
(
type_
);
}
bool
is_arithmetic
()
const
{
return
detai
l
::
is_arithmetic_type
(
type_
);
}
};
/**
...
...
@@ -1091,92 +1152,73 @@ template <typename Context> class basic_format_arg {
\endrst
*/
template
<
typename
Visitor
,
typename
Context
>
FMT_CONSTEXPR
auto
visit_format_arg
(
Visitor
&&
vis
,
const
basic_format_arg
<
Context
>&
arg
)
->
decltype
(
vis
(
0
))
{
FMT_CONSTEXPR_DECL
FMT_INLINE
auto
visit_format_arg
(
Visitor
&&
vis
,
const
basic_format_arg
<
Context
>&
arg
)
->
decltype
(
vis
(
0
))
{
using
char_type
=
typename
Context
::
char_type
;
switch
(
arg
.
type_
)
{
case
interna
l
:
:
type
::
none_type
:
case
detai
l
:
:
type
::
none_type
:
break
;
case
internal
:
:
type
::
named_arg_type
:
FMT_ASSERT
(
false
,
"invalid argument type"
);
break
;
case
internal
:
:
type
::
int_type
:
case
detail
:
:
type
::
int_type
:
return
vis
(
arg
.
value_
.
int_value
);
case
interna
l
:
:
type
::
uint_type
:
case
detai
l
:
:
type
::
uint_type
:
return
vis
(
arg
.
value_
.
uint_value
);
case
interna
l
:
:
type
::
long_long_type
:
case
detai
l
:
:
type
::
long_long_type
:
return
vis
(
arg
.
value_
.
long_long_value
);
case
interna
l
:
:
type
::
ulong_long_type
:
case
detai
l
:
:
type
::
ulong_long_type
:
return
vis
(
arg
.
value_
.
ulong_long_value
);
#if FMT_USE_INT128
case
interna
l
:
:
type
::
int128_type
:
case
detai
l
:
:
type
::
int128_type
:
return
vis
(
arg
.
value_
.
int128_value
);
case
interna
l
:
:
type
::
uint128_type
:
case
detai
l
:
:
type
::
uint128_type
:
return
vis
(
arg
.
value_
.
uint128_value
);
#else
case
interna
l
:
:
type
::
int128_type
:
case
interna
l
:
:
type
::
uint128_type
:
case
detai
l
:
:
type
::
int128_type
:
case
detai
l
:
:
type
::
uint128_type
:
break
;
#endif
case
interna
l
:
:
type
::
bool_type
:
case
detai
l
:
:
type
::
bool_type
:
return
vis
(
arg
.
value_
.
bool_value
);
case
interna
l
:
:
type
::
char_type
:
case
detai
l
:
:
type
::
char_type
:
return
vis
(
arg
.
value_
.
char_value
);
case
interna
l
:
:
type
::
float_type
:
case
detai
l
:
:
type
::
float_type
:
return
vis
(
arg
.
value_
.
float_value
);
case
interna
l
:
:
type
::
double_type
:
case
detai
l
:
:
type
::
double_type
:
return
vis
(
arg
.
value_
.
double_value
);
case
interna
l
:
:
type
::
long_double_type
:
case
detai
l
:
:
type
::
long_double_type
:
return
vis
(
arg
.
value_
.
long_double_value
);
case
interna
l
:
:
type
::
cstring_type
:
case
detai
l
:
:
type
::
cstring_type
:
return
vis
(
arg
.
value_
.
string
.
data
);
case
interna
l
:
:
type
::
string_type
:
case
detai
l
:
:
type
::
string_type
:
return
vis
(
basic_string_view
<
char_type
>
(
arg
.
value_
.
string
.
data
,
arg
.
value_
.
string
.
size
));
case
interna
l
:
:
type
::
pointer_type
:
case
detai
l
:
:
type
::
pointer_type
:
return
vis
(
arg
.
value_
.
pointer
);
case
interna
l
:
:
type
::
custom_type
:
case
detai
l
:
:
type
::
custom_type
:
return
vis
(
typename
basic_format_arg
<
Context
>::
handle
(
arg
.
value_
.
custom
));
}
return
vis
(
monostate
());
}
namespace
internal
{
// A map from argument names to their values for named arguments.
template
<
typename
Context
>
class
arg_map
{
private:
using
char_type
=
typename
Context
::
char_type
;
struct
entry
{
basic_string_view
<
char_type
>
name
;
basic_format_arg
<
Context
>
arg
;
};
// Checks whether T is a container with contiguous storage.
template
<
typename
T
>
struct
is_contiguous
:
std
::
false_type
{};
template
<
typename
Char
>
struct
is_contiguous
<
std
::
basic_string
<
Char
>>
:
std
::
true_type
{};
template
<
typename
Char
>
struct
is_contiguous
<
detail
::
buffer
<
Char
>>
:
std
::
true_type
{};
entry
*
map_
;
unsigned
size_
;
namespace
detail
{
void
push_back
(
value
<
Context
>
val
)
{
const
auto
&
named
=
*
val
.
named_arg
;
map_
[
size_
]
=
{
named
.
name
,
named
.
template
deserialize
<
Context
>()};
++
size_
;
}
template
<
typename
OutputIt
>
struct
is_back_insert_iterator
:
std
::
false_type
{}
;
template
<
typename
Container
>
struct
is_back_insert_iterator
<
std
::
back_insert_iterator
<
Container
>>
:
std
::
true_type
{};
public:
arg_map
(
const
arg_map
&
)
=
delete
;
void
operator
=
(
const
arg_map
&
)
=
delete
;
arg_map
()
:
map_
(
nullptr
),
size_
(
0
)
{}
void
init
(
const
basic_format_args
<
Context
>&
args
);
~
arg_map
()
{
delete
[]
map_
;
}
basic_format_arg
<
Context
>
find
(
basic_string_view
<
char_type
>
name
)
const
{
// The list is unsorted, so just return the first matching name.
for
(
entry
*
it
=
map_
,
*
end
=
map_
+
size_
;
it
!=
end
;
++
it
)
{
if
(
it
->
name
==
name
)
return
it
->
arg
;
}
return
{};
}
};
template
<
typename
OutputIt
>
struct
is_contiguous_back_insert_iterator
:
std
::
false_type
{};
template
<
typename
Container
>
struct
is_contiguous_back_insert_iterator
<
std
::
back_insert_iterator
<
Container
>>
:
is_contiguous
<
Container
>
{};
// A type-erased reference to an std::locale to avoid heavy <locale> include.
class
locale_ref
{
...
...
@@ -1224,10 +1266,14 @@ inline basic_format_arg<Context> make_arg(const T& value) {
}
template
<
typename
T
>
struct
is_reference_wrapper
:
std
::
false_type
{};
template
<
typename
T
>
struct
is_reference_wrapper
<
std
::
reference_wrapper
<
T
>>
:
std
::
true_type
{};
template
<
typename
T
>
const
T
&
unwrap
(
const
T
&
v
)
{
return
v
;
}
template
<
typename
T
>
const
T
&
unwrap
(
const
std
::
reference_wrapper
<
T
>&
v
)
{
return
static_cast
<
const
T
&>
(
v
);
}
class
dynamic_arg_list
{
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
...
...
@@ -1252,14 +1298,14 @@ class dynamic_arg_list {
public:
template
<
typename
T
,
typename
Arg
>
const
T
&
push
(
const
Arg
&
arg
)
{
auto
node
=
std
::
unique_ptr
<
typed_node
<
T
>>
(
new
typed_node
<
T
>
(
arg
));
auto
&
value
=
node
->
value
;
node
->
next
=
std
::
move
(
head_
);
head_
=
std
::
move
(
node
);
auto
n
ew_n
ode
=
std
::
unique_ptr
<
typed_node
<
T
>>
(
new
typed_node
<
T
>
(
arg
));
auto
&
value
=
n
ew_n
ode
->
value
;
n
ew_n
ode
->
next
=
std
::
move
(
head_
);
head_
=
std
::
move
(
n
ew_n
ode
);
return
value
;
}
};
}
// namespace
interna
l
}
// namespace
detai
l
// Formatting context.
template
<
typename
OutputIt
,
typename
Char
>
class
basic_format_context
{
...
...
@@ -1270,8 +1316,7 @@ template <typename OutputIt, typename Char> class basic_format_context {
private:
OutputIt
out_
;
basic_format_args
<
basic_format_context
>
args_
;
internal
::
arg_map
<
basic_format_context
>
map_
;
internal
::
locale_ref
loc_
;
detail
::
locale_ref
loc_
;
public:
using
iterator
=
OutputIt
;
...
...
@@ -1287,34 +1332,38 @@ template <typename OutputIt, typename Char> class basic_format_context {
*/
basic_format_context
(
OutputIt
out
,
basic_format_args
<
basic_format_context
>
ctx_args
,
internal
::
locale_ref
loc
=
interna
l
::
locale_ref
())
detail
::
locale_ref
loc
=
detai
l
::
locale_ref
())
:
out_
(
out
),
args_
(
ctx_args
),
loc_
(
loc
)
{}
format_arg
arg
(
int
id
)
const
{
return
args_
.
get
(
id
);
}
format_arg
arg
(
basic_string_view
<
char_type
>
name
)
{
return
args_
.
get
(
name
);
}
int
arg_id
(
basic_string_view
<
char_type
>
name
)
{
return
args_
.
get_id
(
name
);
}
const
basic_format_args
<
basic_format_context
>&
args
()
const
{
return
args_
;
}
// Checks if manual indexing is used and returns the argument with the
// specified name.
format_arg
arg
(
basic_string_view
<
char_type
>
name
);
internal
::
error_handler
error_handler
()
{
return
{};
}
detail
::
error_handler
error_handler
()
{
return
{};
}
void
on_error
(
const
char
*
message
)
{
error_handler
().
on_error
(
message
);
}
// Returns an iterator to the beginning of the output range.
iterator
out
()
{
return
out_
;
}
// Advances the begin iterator to ``it``.
void
advance_to
(
iterator
it
)
{
out_
=
it
;
}
void
advance_to
(
iterator
it
)
{
if
(
!
detail
::
is_back_insert_iterator
<
iterator
>
())
out_
=
it
;
}
interna
l
::
locale_ref
locale
()
{
return
loc_
;
}
detai
l
::
locale_ref
locale
()
{
return
loc_
;
}
};
template
<
typename
Char
>
using
buffer_context
=
basic_format_context
<
std
::
back_insert_iterator
<
internal
::
buffer
<
Char
>>
,
Char
>
;
basic_format_context
<
std
::
back_insert_iterator
<
detail
::
buffer
<
Char
>>
,
Char
>
;
using
format_context
=
buffer_context
<
char
>
;
using
wformat_context
=
buffer_context
<
wchar_t
>
;
// Workaround a bug in gcc: https://stackoverflow.com/q/62767544/471164.
#define FMT_BUFFER_CONTEXT(Char) \
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>
/**
\rst
An array of references to arguments. It can be implicitly converted into
...
...
@@ -1331,29 +1380,35 @@ class format_arg_store
{
private:
static
const
size_t
num_args
=
sizeof
...(
Args
);
static
const
bool
is_packed
=
num_args
<
internal
::
max_packed_args
;
static
const
size_t
num_named_args
=
detail
::
count_named_args
<
Args
...
>
();
static
const
bool
is_packed
=
num_args
<=
detail
::
max_packed_args
;
using
value_type
=
conditional_t
<
is_packed
,
interna
l
::
value
<
Context
>
,
using
value_type
=
conditional_t
<
is_packed
,
detai
l
::
value
<
Context
>
,
basic_format_arg
<
Context
>>
;
// If the arguments are not packed, add one more element to mark the end.
value_type
data_
[
num_args
+
(
num_args
==
0
?
1
:
0
)];
detail
::
arg_data
<
value_type
,
typename
Context
::
char_type
,
num_args
,
num_named_args
>
data_
;
friend
class
basic_format_args
<
Context
>
;
public:
static
constexpr
unsigned
long
long
types
=
is_packed
?
internal
::
encode_types
<
Context
,
Args
...
>
()
:
internal
::
is_unpacked_bit
|
num_args
;
static
constexpr
unsigned
long
long
desc
=
(
is_packed
?
detail
::
encode_types
<
Context
,
Args
...
>
()
:
detail
::
is_unpacked_bit
|
num_args
)
|
(
num_named_args
!=
0
?
static_cast
<
unsigned
long
long
>
(
detail
::
has_named_args_bit
)
:
0
);
public:
format_arg_store
(
const
Args
&
...
args
)
:
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
basic_format_args
<
Context
>
(
*
this
),
#endif
data_
{
interna
l
::
make_arg
<
data_
{
detai
l
::
make_arg
<
is_packed
,
Context
,
internal
::
mapped_type_constant
<
Args
,
Context
>::
value
>
(
args
)...}
{
detail
::
mapped_type_constant
<
Args
,
Context
>::
value
>
(
args
)...}
{
detail
::
init_named_args
(
data_
.
named_args
(),
0
,
0
,
args
...);
}
};
...
...
@@ -1373,8 +1428,24 @@ inline format_arg_store<Context, Args...> make_format_args(
/**
\rst
A dynamic version of `fmt::format_arg_store<>`.
It's equipped with a storage to potentially temporary objects which lifetime
Returns a named argument to be used in a formatting function. It should only
be used in a call to a formatting function.
**Example**::
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
\endrst
*/
template
<
typename
Char
,
typename
T
>
inline
detail
::
named_arg
<
Char
,
T
>
arg
(
const
Char
*
name
,
const
T
&
arg
)
{
static_assert
(
!
detail
::
is_named_arg
<
T
>
(),
"nested named arguments"
);
return
{
name
,
arg
};
}
/**
\rst
A dynamic version of `fmt::format_arg_store`.
It's equipped with a storage to potentially temporary objects which lifetimes
could be shorter than the format arguments object.
It can be implicitly converted into `~fmt::basic_format_args` for passing
...
...
@@ -1392,49 +1463,73 @@ class dynamic_format_arg_store
using
char_type
=
typename
Context
::
char_type
;
template
<
typename
T
>
struct
need_copy
{
static
constexpr
interna
l
::
type
mapped_type
=
interna
l
::
mapped_type_constant
<
T
,
Context
>::
value
;
static
constexpr
detai
l
::
type
mapped_type
=
detai
l
::
mapped_type_constant
<
T
,
Context
>::
value
;
enum
{
value
=
!
(
interna
l
::
is_reference_wrapper
<
T
>::
value
||
value
=
!
(
detai
l
::
is_reference_wrapper
<
T
>::
value
||
std
::
is_same
<
T
,
basic_string_view
<
char_type
>>::
value
||
std
::
is_same
<
T
,
internal
::
std_string_view
<
char_type
>>::
value
||
(
mapped_type
!=
internal
::
type
::
cstring_type
&&
mapped_type
!=
internal
::
type
::
string_type
&&
mapped_type
!=
internal
::
type
::
custom_type
&&
mapped_type
!=
internal
::
type
::
named_arg_type
))
std
::
is_same
<
T
,
detail
::
std_string_view
<
char_type
>>::
value
||
(
mapped_type
!=
detail
::
type
::
cstring_type
&&
mapped_type
!=
detail
::
type
::
string_type
&&
mapped_type
!=
detail
::
type
::
custom_type
))
};
};
template
<
typename
T
>
using
stored_type
=
conditional_t
<
interna
l
::
is_string
<
T
>::
value
,
using
stored_type
=
conditional_t
<
detai
l
::
is_string
<
T
>::
value
,
std
::
basic_string
<
char_type
>
,
T
>
;
// Storage of basic_format_arg must be contiguous.
std
::
vector
<
basic_format_arg
<
Context
>>
data_
;
std
::
vector
<
detail
::
named_arg_info
<
char_type
>>
named_info_
;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
interna
l
::
dynamic_arg_list
dynamic_args_
;
detai
l
::
dynamic_arg_list
dynamic_args_
;
friend
class
basic_format_args
<
Context
>
;
unsigned
long
long
get_types
()
const
{
return
internal
::
is_unpacked_bit
|
data_
.
size
();
return
detail
::
is_unpacked_bit
|
data_
.
size
()
|
(
named_info_
.
empty
()
?
0ULL
:
static_cast
<
unsigned
long
long
>
(
detail
::
has_named_args_bit
));
}
const
basic_format_arg
<
Context
>*
data
()
const
{
return
named_info_
.
empty
()
?
data_
.
data
()
:
data_
.
data
()
+
1
;
}
template
<
typename
T
>
void
emplace_arg
(
const
T
&
arg
)
{
data_
.
emplace_back
(
internal
::
make_arg
<
Context
>
(
arg
));
data_
.
emplace_back
(
detail
::
make_arg
<
Context
>
(
arg
));
}
template
<
typename
T
>
void
emplace_arg
(
const
detail
::
named_arg
<
char_type
,
T
>&
arg
)
{
if
(
named_info_
.
empty
())
{
constexpr
const
detail
::
named_arg_info
<
char_type
>*
zero_ptr
{
nullptr
};
data_
.
insert
(
data_
.
begin
(),
{
zero_ptr
,
0
});
}
data_
.
emplace_back
(
detail
::
make_arg
<
Context
>
(
detail
::
unwrap
(
arg
.
value
)));
auto
pop_one
=
[](
std
::
vector
<
basic_format_arg
<
Context
>>*
data
)
{
data
->
pop_back
();
};
std
::
unique_ptr
<
std
::
vector
<
basic_format_arg
<
Context
>>
,
decltype
(
pop_one
)
>
guard
{
&
data_
,
pop_one
};
named_info_
.
push_back
({
arg
.
name
,
static_cast
<
int
>
(
data_
.
size
()
-
2u
)});
data_
[
0
].
value_
.
named_args
=
{
named_info_
.
data
(),
named_info_
.
size
()};
guard
.
release
();
}
public:
/**
\rst
Adds an argument into the dynamic store for later passing to a formating
Adds an argument into the dynamic store for later passing to a format
t
ing
function.
Note that custom types and string types (but not string views
!
) are copied
into the store
with dynamic memory (in addition to resizing vector)
.
Note that custom types and string types (but not string views) are copied
into the store
dynamically allocating memory if necessary
.
**Example**::
...
...
@@ -1446,25 +1541,78 @@ class dynamic_format_arg_store
\endrst
*/
template
<
typename
T
>
void
push_back
(
const
T
&
arg
)
{
static_assert
(
!
std
::
is_base_of
<
internal
::
named_arg_base
<
char_type
>
,
T
>::
value
,
"named arguments are not supported yet"
);
if
(
internal
::
const_check
(
need_copy
<
T
>::
value
))
if
(
detail
::
const_check
(
need_copy
<
T
>::
value
))
emplace_arg
(
dynamic_args_
.
push
<
stored_type
<
T
>>
(
arg
));
else
emplace_arg
(
arg
);
emplace_arg
(
detail
::
unwrap
(
arg
)
);
}
/**
\rst
Adds a reference to the argument into the dynamic store for later passing to
a formating function.
a formatting function. Supports named arguments wrapped in
``std::reference_wrapper`` via ``std::ref()``/``std::cref()``.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
char str[] = "1234567890";
store.push_back(std::cref(str));
int a1_val{42};
auto a1 = fmt::arg("a1_", a1_val);
store.push_back(std::cref(a1));
// Changing str affects the output but only for string and custom types.
str[0] = 'X';
std::string result = fmt::vformat("{} and {a1_}");
assert(result == "X234567890 and 42");
\endrst
*/
template
<
typename
T
>
void
push_back
(
std
::
reference_wrapper
<
T
>
arg
)
{
static_assert
(
need_copy
<
T
>::
value
,
detail
::
is_named_arg
<
typename
std
::
remove_cv
<
T
>::
type
>::
value
||
need_copy
<
T
>::
value
,
"objects of built-in types and string views are always copied"
);
emplace_arg
(
arg
.
get
());
}
/**
Adds named argument into the dynamic store for later passing to a formatting
function. ``std::reference_wrapper`` is supported to avoid copying of the
argument.
*/
template
<
typename
T
>
void
push_back
(
const
detail
::
named_arg
<
char_type
,
T
>&
arg
)
{
const
char_type
*
arg_name
=
dynamic_args_
.
push
<
std
::
basic_string
<
char_type
>>
(
arg
.
name
).
c_str
();
if
(
detail
::
const_check
(
need_copy
<
T
>::
value
))
{
emplace_arg
(
fmt
::
arg
(
arg_name
,
dynamic_args_
.
push
<
stored_type
<
T
>>
(
arg
.
value
)));
}
else
{
emplace_arg
(
fmt
::
arg
(
arg_name
,
arg
.
value
));
}
}
/** Erase all elements from the store */
void
clear
()
{
data_
.
clear
();
named_info_
.
clear
();
dynamic_args_
=
detail
::
dynamic_arg_list
();
}
/**
\rst
Reserves space to store at least *new_cap* arguments including
*new_cap_named* named arguments.
\endrst
*/
void
reserve
(
size_t
new_cap
,
size_t
new_cap_named
)
{
FMT_ASSERT
(
new_cap
>=
new_cap_named
,
"Set of arguments includes set of named arguments"
);
data_
.
reserve
(
new_cap
);
named_info_
.
reserve
(
new_cap_named
);
}
};
/**
...
...
@@ -1483,49 +1631,40 @@ template <typename Context> class basic_format_args {
using
format_arg
=
basic_format_arg
<
Context
>
;
private:
// To reduce compiled code size per formatting function call, types of first
// max_packed_args arguments are passed in the types_ field.
unsigned
long
long
types_
;
// A descriptor that contains information about formatting arguments.
// If the number of arguments is less or equal to max_packed_args then
// argument types are passed in the descriptor. This reduces binary code size
// per formatting function call.
unsigned
long
long
desc_
;
union
{
// If
the number of arguments is less than max_packed_args, the argument
//
values are stored in values_, otherwise they are stored in args_.
//
This is done to reduce compiled code size as
storing larger objects
// If
is_packed() returns true then argument values are stored in values_;
//
otherwise they are stored in args_. This is done to improve cache
//
locality and reduce compiled code size since
storing larger objects
// may require more code (at least on x86-64) even if the same amount of
// data is actually copied to stack. It saves ~10% on the bloat test.
const
interna
l
::
value
<
Context
>*
values_
;
const
detai
l
::
value
<
Context
>*
values_
;
const
format_arg
*
args_
;
};
bool
is_packed
()
const
{
return
(
types_
&
internal
::
is_unpacked_bit
)
==
0
;
}
internal
::
type
type
(
int
index
)
const
{
int
shift
=
index
*
internal
::
packed_arg_bits
;
unsigned
int
mask
=
(
1
<<
internal
::
packed_arg_bits
)
-
1
;
return
static_cast
<
internal
::
type
>
((
types_
>>
shift
)
&
mask
);
bool
is_packed
()
const
{
return
(
desc_
&
detail
::
is_unpacked_bit
)
==
0
;
}
bool
has_named_args
()
const
{
return
(
desc_
&
detail
::
has_named_args_bit
)
!=
0
;
}
friend
class
internal
::
arg_map
<
Context
>
;
void
set_data
(
const
internal
::
value
<
Context
>*
values
)
{
values_
=
values
;
}
void
set_data
(
const
format_arg
*
args
)
{
args_
=
args
;
}
format_arg
do_get
(
int
index
)
const
{
format_arg
arg
;
if
(
!
is_packed
())
{
auto
num_args
=
max_size
();
if
(
index
<
num_args
)
arg
=
args_
[
index
];
return
arg
;
}
if
(
index
>
internal
::
max_packed_args
)
return
arg
;
arg
.
type_
=
type
(
index
);
if
(
arg
.
type_
==
internal
::
type
::
none_type
)
return
arg
;
internal
::
value
<
Context
>&
val
=
arg
.
value_
;
val
=
values_
[
index
];
return
arg
;
detail
::
type
type
(
int
index
)
const
{
int
shift
=
index
*
detail
::
packed_arg_bits
;
unsigned
int
mask
=
(
1
<<
detail
::
packed_arg_bits
)
-
1
;
return
static_cast
<
detail
::
type
>
((
desc_
>>
shift
)
&
mask
);
}
basic_format_args
(
unsigned
long
long
desc
,
const
detail
::
value
<
Context
>*
values
)
:
desc_
(
desc
),
values_
(
values
)
{}
basic_format_args
(
unsigned
long
long
desc
,
const
format_arg
*
args
)
:
desc_
(
desc
),
args_
(
args
)
{}
public:
basic_format_args
()
:
types
_
(
0
)
{}
basic_format_args
()
:
desc
_
(
0
)
{}
/**
\rst
...
...
@@ -1533,10 +1672,8 @@ template <typename Context> class basic_format_args {
\endrst
*/
template
<
typename
...
Args
>
basic_format_args
(
const
format_arg_store
<
Context
,
Args
...
>&
store
)
:
types_
(
store
.
types
)
{
set_data
(
store
.
data_
);
}
FMT_INLINE
basic_format_args
(
const
format_arg_store
<
Context
,
Args
...
>&
store
)
:
basic_format_args
(
store
.
desc
,
store
.
data_
.
args
())
{}
/**
\rst
...
...
@@ -1544,10 +1681,8 @@ template <typename Context> class basic_format_args {
`~fmt::dynamic_format_arg_store`.
\endrst
*/
basic_format_args
(
const
dynamic_format_arg_store
<
Context
>&
store
)
:
types_
(
store
.
get_types
())
{
set_data
(
store
.
data_
.
data
());
}
FMT_INLINE
basic_format_args
(
const
dynamic_format_arg_store
<
Context
>&
store
)
:
basic_format_args
(
store
.
get_types
(),
store
.
data
())
{}
/**
\rst
...
...
@@ -1555,22 +1690,42 @@ template <typename Context> class basic_format_args {
\endrst
*/
basic_format_args
(
const
format_arg
*
args
,
int
count
)
:
types_
(
internal
::
is_unpacked_bit
|
internal
::
to_unsigned
(
count
))
{
set_data
(
args
);
}
:
basic_format_args
(
detail
::
is_unpacked_bit
|
detail
::
to_unsigned
(
count
),
args
)
{}
/** Returns the argument at specified index. */
format_arg
get
(
int
index
)
const
{
format_arg
arg
=
do_get
(
index
);
if
(
arg
.
type_
==
internal
::
type
::
named_arg_type
)
arg
=
arg
.
value_
.
named_arg
->
template
deserialize
<
Context
>();
/** Returns the argument with the specified id. */
format_arg
get
(
int
id
)
const
{
format_arg
arg
;
if
(
!
is_packed
())
{
if
(
id
<
max_size
())
arg
=
args_
[
id
];
return
arg
;
}
if
(
id
>=
detail
::
max_packed_args
)
return
arg
;
arg
.
type_
=
type
(
id
);
if
(
arg
.
type_
==
detail
::
type
::
none_type
)
return
arg
;
arg
.
value_
=
values_
[
id
];
return
arg
;
}
template
<
typename
Char
>
format_arg
get
(
basic_string_view
<
Char
>
name
)
const
{
int
id
=
get_id
(
name
);
return
id
>=
0
?
get
(
id
)
:
format_arg
();
}
template
<
typename
Char
>
int
get_id
(
basic_string_view
<
Char
>
name
)
const
{
if
(
!
has_named_args
())
return
-
1
;
const
auto
&
named_args
=
(
is_packed
()
?
values_
[
-
1
]
:
args_
[
-
1
].
value_
).
named_args
;
for
(
size_t
i
=
0
;
i
<
named_args
.
size
;
++
i
)
{
if
(
named_args
.
data
[
i
].
name
==
name
)
return
named_args
.
data
[
i
].
id
;
}
return
-
1
;
}
int
max_size
()
const
{
unsigned
long
long
max_packed
=
interna
l
::
max_packed_args
;
unsigned
long
long
max_packed
=
detai
l
::
max_packed_args
;
return
static_cast
<
int
>
(
is_packed
()
?
max_packed
:
types_
&
~
interna
l
::
is_unpacked_bit
);
:
desc_
&
~
detai
l
::
is_unpacked_bit
);
}
};
...
...
@@ -1578,93 +1733,48 @@ template <typename Context> class basic_format_args {
// It is a separate type rather than an alias to make symbols readable.
struct
format_args
:
basic_format_args
<
format_context
>
{
template
<
typename
...
Args
>
format_args
(
Args
&&
...
args
)
:
basic_format_args
<
format_context
>
(
static_cast
<
Args
&&>
(
args
)...)
{}
FMT_INLINE
format_args
(
const
Args
&
...
args
)
:
basic_format_args
(
args
...)
{}
};
struct
wformat_args
:
basic_format_args
<
wformat_context
>
{
template
<
typename
...
Args
>
wformat_args
(
Args
&&
...
args
)
:
basic_format_args
<
wformat_context
>
(
static_cast
<
Args
&&>
(
args
)...)
{}
using
basic_format_args
::
basic_format_args
;
};
template
<
typename
Container
>
struct
is_contiguous
:
std
::
false_type
{};
template
<
typename
Char
>
struct
is_contiguous
<
std
::
basic_string
<
Char
>>
:
std
::
true_type
{};
template
<
typename
Char
>
struct
is_contiguous
<
internal
::
buffer
<
Char
>>
:
std
::
true_type
{};
namespace
internal
{
template
<
typename
OutputIt
>
struct
is_contiguous_back_insert_iterator
:
std
::
false_type
{};
template
<
typename
Container
>
struct
is_contiguous_back_insert_iterator
<
std
::
back_insert_iterator
<
Container
>>
:
is_contiguous
<
Container
>
{};
template
<
typename
Char
>
struct
named_arg_base
{
basic_string_view
<
Char
>
name
;
// Serialized value<context>.
mutable
char
data
[
sizeof
(
basic_format_arg
<
buffer_context
<
Char
>>
)];
named_arg_base
(
basic_string_view
<
Char
>
nm
)
:
name
(
nm
)
{}
template
<
typename
Context
>
basic_format_arg
<
Context
>
deserialize
()
const
{
basic_format_arg
<
Context
>
arg
;
std
::
memcpy
(
&
arg
,
data
,
sizeof
(
basic_format_arg
<
Context
>
));
return
arg
;
}
};
struct
view
{};
template
<
typename
T
,
typename
Char
>
struct
named_arg
:
view
,
named_arg_base
<
Char
>
{
const
T
&
value
;
named_arg
(
basic_string_view
<
Char
>
name
,
const
T
&
val
)
:
named_arg_base
<
Char
>
(
name
),
value
(
val
)
{}
};
namespace
detail
{
// Reports a compile-time error if S is not a valid format string.
template
<
typename
...
,
typename
S
,
FMT_ENABLE_IF
(
!
is_compile_string
<
S
>
::
value
)
>
inline
void
check_format_string
(
const
S
&
)
{
#if
defined(FMT_ENFORCE_COMPILE_STRING)
FMT_INLINE
void
check_format_string
(
const
S
&
)
{
#if
def FMT_ENFORCE_COMPILE_STRING
static_assert
(
is_compile_string
<
S
>::
value
,
"FMT_ENFORCE_COMPILE_STRING requires all format strings to "
"
utilize FMT_STRING() or fmt()
."
);
"FMT_ENFORCE_COMPILE_STRING requires all format strings to
use
"
"
FMT_STRING
."
);
#endif
}
template
<
typename
...
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
void
check_format_string
(
S
);
template
<
bool
...>
struct
bool_pack
;
template
<
bool
...
Args
>
using
all_true
=
std
::
is_same
<
bool_pack
<
Args
...,
true
>
,
bool_pack
<
true
,
Args
...
>>
;
template
<
typename
...
Args
,
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
format_arg_store
<
buffer_context
<
Char
>
,
remove_reference_t
<
Args
>
...
>
make_args_checked
(
const
S
&
format_str
,
const
remove_reference_t
<
Args
>&
...
args
)
{
static_assert
(
all_true
<
(
!
std
::
is_base_of
<
view
,
remove_reference_t
<
Args
>>::
value
||
!
std
::
is_reference
<
Args
>::
value
)...
>::
value
,
"passing views as lvalues is disallowed"
);
static_assert
(
count
<
(
std
::
is_base_of
<
view
,
remove_reference_t
<
Args
>>::
value
&&
std
::
is_reference
<
Args
>::
value
)...
>
()
==
0
,
"passing views as lvalues is disallowed"
);
check_format_string
<
Args
...
>
(
format_str
);
return
{
args
...};
}
template
<
typename
Char
>
template
<
typename
Char
,
FMT_ENABLE_IF
(
!
std
::
is_same
<
Char
,
char
>
::
value
)
>
std
::
basic_string
<
Char
>
vformat
(
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
);
FMT_API
std
::
string
vformat
(
string_view
format_str
,
format_args
args
);
template
<
typename
Char
>
typename
buffer_context
<
Char
>
::
iterator
vformat_to
(
typename
FMT_BUFFER_CONTEXT
(
Char
)
::
iterator
vformat_to
(
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>
>
args
);
basic_format_args
<
FMT_BUFFER_CONTEXT
(
type_identity_t
<
Char
>
)
>
args
);
template
<
typename
Char
,
typename
Args
,
FMT_ENABLE_IF
(
!
std
::
is_same
<
Char
,
char
>
::
value
)
>
...
...
@@ -1674,58 +1784,38 @@ FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
#ifndef _WIN32
inline
void
vprint_mojibake
(
std
::
FILE
*
,
string_view
,
format_args
)
{}
#endif
}
// namespace internal
/**
\rst
Returns a named argument to be used in a formatting function. It should only
be used in a call to a formatting function.
**Example**::
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
\endrst
*/
template
<
typename
S
,
typename
T
,
typename
Char
=
char_t
<
S
>
>
inline
internal
::
named_arg
<
T
,
Char
>
arg
(
const
S
&
name
,
const
T
&
arg
)
{
static_assert
(
internal
::
is_string
<
S
>::
value
,
""
);
return
{
name
,
arg
};
}
// Disable nested named arguments, e.g. ``arg("a", arg("b", 42))``.
template
<
typename
S
,
typename
T
,
typename
Char
>
void
arg
(
S
,
internal
::
named_arg
<
T
,
Char
>
)
=
delete
;
}
// namespace detail
/** Formats a string and writes the output to ``out``. */
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
template
<
typename
OutputIt
,
typename
S
,
typename
Char
=
char_t
<
S
>,
FMT_ENABLE_IF
(
interna
l
::
is_contiguous_back_insert_iterator
<
OutputIt
>::
value
)
>
template
<
typename
OutputIt
,
typename
S
,
typename
Char
=
char_t
<
S
>,
FMT_ENABLE_IF
(
detai
l
::
is_contiguous_back_insert_iterator
<
OutputIt
>::
value
)
>
OutputIt
vformat_to
(
OutputIt
out
,
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
using
container
=
remove_reference_t
<
decltype
(
internal
::
get_container
(
out
))
>
;
internal
::
container_buffer
<
container
>
buf
((
internal
::
get_container
(
out
))
);
interna
l
::
vformat_to
(
buf
,
to_string_view
(
format_str
),
args
);
auto
&
c
=
detail
::
get_container
(
out
)
;
detail
::
container_buffer
<
remove_reference_t
<
decltype
(
c
)
>>
buf
(
c
);
detai
l
::
vformat_to
(
buf
,
to_string_view
(
format_str
),
args
);
return
out
;
}
template
<
typename
Container
,
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
is_contiguous
<
Container
>
::
value
&&
interna
l
::
is_string
<
S
>::
value
)
>
is_contiguous
<
Container
>
::
value
&&
detai
l
::
is_string
<
S
>::
value
)
>
inline
std
::
back_insert_iterator
<
Container
>
format_to
(
std
::
back_insert_iterator
<
Container
>
out
,
const
S
&
format_str
,
Args
&&
...
args
)
{
return
vformat_to
(
out
,
to_string_view
(
format_str
),
interna
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
detai
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
}
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
vformat
(
FMT_INLINE
std
::
basic_string
<
Char
>
vformat
(
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
return
interna
l
::
vformat
(
to_string_view
(
format_str
),
args
);
return
detai
l
::
vformat
(
to_string_view
(
format_str
),
args
);
}
/**
...
...
@@ -1741,10 +1831,9 @@ inline std::basic_string<Char> vformat(
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
format
(
const
S
&
format_str
,
Args
&&
...
args
)
{
return
internal
::
vformat
(
to_string_view
(
format_str
),
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
FMT_INLINE
std
::
basic_string
<
Char
>
format
(
const
S
&
format_str
,
Args
&&
...
args
)
{
const
auto
&
vargs
=
detail
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...);
return
detail
::
vformat
(
to_string_view
(
format_str
),
vargs
);
}
FMT_API
void
vprint
(
string_view
,
format_args
);
...
...
@@ -1763,12 +1852,10 @@ FMT_API void vprint(std::FILE*, string_view, format_args);
*/
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
char_t
<
S
>
>
inline
void
print
(
std
::
FILE
*
f
,
const
S
&
format_str
,
Args
&&
...
args
)
{
return
internal
::
is_unicode
<
Char
>
()
?
vprint
(
f
,
to_string_view
(
format_str
),
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...))
:
internal
::
vprint_mojibake
(
f
,
to_string_view
(
format_str
),
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
const
auto
&
vargs
=
detail
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...);
return
detail
::
is_unicode
<
Char
>
()
?
vprint
(
f
,
to_string_view
(
format_str
),
vargs
)
:
detail
::
vprint_mojibake
(
f
,
to_string_view
(
format_str
),
vargs
);
}
/**
...
...
@@ -1784,12 +1871,11 @@ inline void print(std::FILE* f, const S& format_str, Args&&... args) {
*/
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
char_t
<
S
>
>
inline
void
print
(
const
S
&
format_str
,
Args
&&
...
args
)
{
return
internal
::
is_unicode
<
Char
>
()
?
vprint
(
to_string_view
(
format_str
),
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...))
:
internal
::
vprint_mojibake
(
stdout
,
to_string_view
(
format_str
),
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
const
auto
&
vargs
=
detail
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...);
return
detail
::
is_unicode
<
Char
>
()
?
vprint
(
to_string_view
(
format_str
),
vargs
)
:
detail
::
vprint_mojibake
(
stdout
,
to_string_view
(
format_str
),
vargs
);
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/format-inl.h
View file @
23c2c00d
...
...
@@ -15,6 +15,7 @@
#include <cstdarg>
#include <cstring> // for std::memmove
#include <cwchar>
#include <exception>
#include "format.h"
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
...
...
@@ -22,8 +23,16 @@
#endif
#ifdef _WIN32
# if !defined(NOMINMAX) && !defined(WIN32_LEAN_AND_MEAN)
# define NOMINMAX
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
# undef NOMINMAX
# else
# include <windows.h>
# endif
# include <io.h>
# include <windows.h>
#endif
#ifdef _MSC_VER
...
...
@@ -33,15 +42,19 @@
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
inline
fmt
::
interna
l
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
return
{};
}
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
{};
}
inline
fmt
::
detai
l
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
return
{};
}
inline
fmt
::
detail
::
null
<>
strerror_s
(
char
*
,
size_t
,
...)
{
return
{};
}
FMT_BEGIN_NAMESPACE
namespace
interna
l
{
namespace
detai
l
{
FMT_FUNC
void
assert_fail
(
const
char
*
file
,
int
line
,
const
char
*
message
)
{
print
(
stderr
,
"{}:{}: assertion failed: {}"
,
file
,
line
,
message
);
std
::
abort
();
// Use unchecked std::fprintf to avoid triggering another assertion when
// writing to stderr fails
std
::
fprintf
(
stderr
,
"%s:%d: assertion failed: %s"
,
file
,
line
,
message
);
// Chosen instead of std::abort to satisfy Clang in CUDA mode during device
// code pass.
std
::
terminate
();
}
#ifndef _MSC_VER
...
...
@@ -67,14 +80,14 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
// other - failure
// Buffer should be at least of size 1.
FMT_FUNC
int
safe_strerror
(
int
error_code
,
char
*&
buffer
,
s
td
::
s
ize_t
buffer_size
)
FMT_NOEXCEPT
{
size_t
buffer_size
)
FMT_NOEXCEPT
{
FMT_ASSERT
(
buffer
!=
nullptr
&&
buffer_size
!=
0
,
"invalid buffer"
);
class
dispatcher
{
private:
int
error_code_
;
char
*&
buffer_
;
s
td
::
s
ize_t
buffer_size_
;
size_t
buffer_size_
;
// A noop assignment operator to avoid bogus warnings.
void
operator
=
(
const
dispatcher
&
)
{}
...
...
@@ -97,7 +110,7 @@ FMT_FUNC int safe_strerror(int error_code, char*& buffer,
// Handle the case when strerror_r is not available.
FMT_MAYBE_UNUSED
int
handle
(
interna
l
::
null
<>
)
{
int
handle
(
detai
l
::
null
<>
)
{
return
fallback
(
strerror_s
(
buffer_
,
buffer_size_
,
error_code_
));
}
...
...
@@ -111,7 +124,7 @@ FMT_FUNC int safe_strerror(int error_code, char*& buffer,
#if !FMT_MSC_VER
// Fallback to strerror if strerror_r and strerror_s are not available.
int
fallback
(
interna
l
::
null
<>
)
{
int
fallback
(
detai
l
::
null
<>
)
{
errno
=
0
;
buffer_
=
strerror
(
error_code_
);
return
errno
;
...
...
@@ -119,7 +132,7 @@ FMT_FUNC int safe_strerror(int error_code, char*& buffer,
#endif
public:
dispatcher
(
int
err_code
,
char
*&
buf
,
s
td
::
s
ize_t
buf_size
)
dispatcher
(
int
err_code
,
char
*&
buf
,
size_t
buf_size
)
:
error_code_
(
err_code
),
buffer_
(
buf
),
buffer_size_
(
buf_size
)
{}
int
run
()
{
return
handle
(
strerror_r
(
error_code_
,
buffer_
,
buffer_size_
));
}
...
...
@@ -127,7 +140,7 @@ FMT_FUNC int safe_strerror(int error_code, char*& buffer,
return
dispatcher
(
error_code
,
buffer
,
buffer_size
).
run
();
}
FMT_FUNC
void
format_error_code
(
interna
l
::
buffer
<
char
>&
out
,
int
error_code
,
FMT_FUNC
void
format_error_code
(
detai
l
::
buffer
<
char
>&
out
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
// Report error code making sure that the output fits into
// inline_buffer_size to avoid dynamic memory allocation and potential
...
...
@@ -136,20 +149,17 @@ FMT_FUNC void format_error_code(internal::buffer<char>& out, int error_code,
static
const
char
SEP
[]
=
": "
;
static
const
char
ERROR_STR
[]
=
"error "
;
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
s
td
::
s
ize_t
error_code_size
=
sizeof
(
SEP
)
+
sizeof
(
ERROR_STR
)
-
2
;
size_t
error_code_size
=
sizeof
(
SEP
)
+
sizeof
(
ERROR_STR
)
-
2
;
auto
abs_value
=
static_cast
<
uint32_or_64_or_128_t
<
int
>>
(
error_code
);
if
(
interna
l
::
is_negative
(
error_code
))
{
if
(
detai
l
::
is_negative
(
error_code
))
{
abs_value
=
0
-
abs_value
;
++
error_code_size
;
}
error_code_size
+=
internal
::
to_unsigned
(
internal
::
count_digits
(
abs_value
));
internal
::
writer
w
(
out
);
if
(
message
.
size
()
<=
inline_buffer_size
-
error_code_size
)
{
w
.
write
(
message
);
w
.
write
(
SEP
);
}
w
.
write
(
ERROR_STR
);
w
.
write
(
error_code
);
error_code_size
+=
detail
::
to_unsigned
(
detail
::
count_digits
(
abs_value
));
auto
it
=
std
::
back_inserter
(
out
);
if
(
message
.
size
()
<=
inline_buffer_size
-
error_code_size
)
format_to
(
it
,
"{}{}"
,
message
,
SEP
);
format_to
(
it
,
"{}{}"
,
ERROR_STR
,
error_code
);
assert
(
out
.
size
()
<=
inline_buffer_size
);
}
...
...
@@ -168,10 +178,10 @@ FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
size_t
written
=
std
::
fwrite
(
ptr
,
size
,
count
,
stream
);
if
(
written
<
count
)
FMT_THROW
(
system_error
(
errno
,
"cannot write to file"
));
}
}
// namespace
interna
l
}
// namespace
detai
l
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace
interna
l
{
namespace
detai
l
{
template
<
typename
Locale
>
locale_ref
::
locale_ref
(
const
Locale
&
loc
)
:
locale_
(
&
loc
)
{
...
...
@@ -194,18 +204,16 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
return
std
::
use_facet
<
std
::
numpunct
<
Char
>>
(
loc
.
get
<
std
::
locale
>
())
.
decimal_point
();
}
}
// namespace
interna
l
}
// namespace
detai
l
#else
template
<
typename
Char
>
FMT_FUNC
std
::
string
interna
l
::
grouping_impl
(
locale_ref
)
{
FMT_FUNC
std
::
string
detai
l
::
grouping_impl
(
locale_ref
)
{
return
"
\03
"
;
}
template
<
typename
Char
>
FMT_FUNC
Char
internal
::
thousands_sep_impl
(
locale_ref
)
{
template
<
typename
Char
>
FMT_FUNC
Char
detail
::
thousands_sep_impl
(
locale_ref
)
{
return
FMT_STATIC_THOUSANDS_SEPARATOR
;
}
template
<
typename
Char
>
FMT_FUNC
Char
internal
::
decimal_point_impl
(
locale_ref
)
{
template
<
typename
Char
>
FMT_FUNC
Char
detail
::
decimal_point_impl
(
locale_ref
)
{
return
'.'
;
}
#endif
...
...
@@ -222,9 +230,9 @@ FMT_FUNC void system_error::init(int err_code, string_view format_str,
base
=
std
::
runtime_error
(
to_string
(
buffer
));
}
namespace
interna
l
{
namespace
detai
l
{
template
<
>
FMT_FUNC
int
count_digits
<
4
>
(
interna
l
::
fallback_uintptr
n
)
{
template
<
>
FMT_FUNC
int
count_digits
<
4
>
(
detai
l
::
fallback_uintptr
n
)
{
// fallback_uintptr is always stored in little endian.
int
i
=
static_cast
<
int
>
(
sizeof
(
void
*
))
-
1
;
while
(
i
>
0
&&
n
.
value
[
i
]
==
0
)
--
i
;
...
...
@@ -233,12 +241,27 @@ template <> FMT_FUNC int count_digits<4>(internal::fallback_uintptr n) {
}
template
<
typename
T
>
const
char
basic_data
<
T
>::
digits
[]
=
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899"
;
const
typename
basic_data
<
T
>::
digit_pair
basic_data
<
T
>::
digits
[]
=
{
{
'0'
,
'0'
},
{
'0'
,
'1'
},
{
'0'
,
'2'
},
{
'0'
,
'3'
},
{
'0'
,
'4'
},
{
'0'
,
'5'
},
{
'0'
,
'6'
},
{
'0'
,
'7'
},
{
'0'
,
'8'
},
{
'0'
,
'9'
},
{
'1'
,
'0'
},
{
'1'
,
'1'
},
{
'1'
,
'2'
},
{
'1'
,
'3'
},
{
'1'
,
'4'
},
{
'1'
,
'5'
},
{
'1'
,
'6'
},
{
'1'
,
'7'
},
{
'1'
,
'8'
},
{
'1'
,
'9'
},
{
'2'
,
'0'
},
{
'2'
,
'1'
},
{
'2'
,
'2'
},
{
'2'
,
'3'
},
{
'2'
,
'4'
},
{
'2'
,
'5'
},
{
'2'
,
'6'
},
{
'2'
,
'7'
},
{
'2'
,
'8'
},
{
'2'
,
'9'
},
{
'3'
,
'0'
},
{
'3'
,
'1'
},
{
'3'
,
'2'
},
{
'3'
,
'3'
},
{
'3'
,
'4'
},
{
'3'
,
'5'
},
{
'3'
,
'6'
},
{
'3'
,
'7'
},
{
'3'
,
'8'
},
{
'3'
,
'9'
},
{
'4'
,
'0'
},
{
'4'
,
'1'
},
{
'4'
,
'2'
},
{
'4'
,
'3'
},
{
'4'
,
'4'
},
{
'4'
,
'5'
},
{
'4'
,
'6'
},
{
'4'
,
'7'
},
{
'4'
,
'8'
},
{
'4'
,
'9'
},
{
'5'
,
'0'
},
{
'5'
,
'1'
},
{
'5'
,
'2'
},
{
'5'
,
'3'
},
{
'5'
,
'4'
},
{
'5'
,
'5'
},
{
'5'
,
'6'
},
{
'5'
,
'7'
},
{
'5'
,
'8'
},
{
'5'
,
'9'
},
{
'6'
,
'0'
},
{
'6'
,
'1'
},
{
'6'
,
'2'
},
{
'6'
,
'3'
},
{
'6'
,
'4'
},
{
'6'
,
'5'
},
{
'6'
,
'6'
},
{
'6'
,
'7'
},
{
'6'
,
'8'
},
{
'6'
,
'9'
},
{
'7'
,
'0'
},
{
'7'
,
'1'
},
{
'7'
,
'2'
},
{
'7'
,
'3'
},
{
'7'
,
'4'
},
{
'7'
,
'5'
},
{
'7'
,
'6'
},
{
'7'
,
'7'
},
{
'7'
,
'8'
},
{
'7'
,
'9'
},
{
'8'
,
'0'
},
{
'8'
,
'1'
},
{
'8'
,
'2'
},
{
'8'
,
'3'
},
{
'8'
,
'4'
},
{
'8'
,
'5'
},
{
'8'
,
'6'
},
{
'8'
,
'7'
},
{
'8'
,
'8'
},
{
'8'
,
'9'
},
{
'9'
,
'0'
},
{
'9'
,
'1'
},
{
'9'
,
'2'
},
{
'9'
,
'3'
},
{
'9'
,
'4'
},
{
'9'
,
'5'
},
{
'9'
,
'6'
},
{
'9'
,
'7'
},
{
'9'
,
'8'
},
{
'9'
,
'9'
}};
template
<
typename
T
>
const
char
basic_data
<
T
>::
hex_digits
[]
=
"0123456789abcdef"
;
...
...
@@ -317,6 +340,10 @@ const char basic_data<T>::background_color[] = "\x1b[48;2;";
template
<
typename
T
>
const
char
basic_data
<
T
>::
reset_color
[]
=
"
\x1b
[0m"
;
template
<
typename
T
>
const
wchar_t
basic_data
<
T
>::
wreset_color
[]
=
L"
\x1b
[0m"
;
template
<
typename
T
>
const
char
basic_data
<
T
>::
signs
[]
=
{
0
,
'-'
,
'+'
,
' '
};
template
<
typename
T
>
const
char
basic_data
<
T
>::
left_padding_shifts
[]
=
{
31
,
31
,
0
,
1
,
0
};
template
<
typename
T
>
const
char
basic_data
<
T
>::
right_padding_shifts
[]
=
{
0
,
31
,
0
,
1
,
0
};
template
<
typename
T
>
struct
bits
{
static
FMT_CONSTEXPR_DECL
const
int
value
=
...
...
@@ -576,9 +603,10 @@ class bigint {
void
operator
=
(
const
bigint
&
)
=
delete
;
void
assign
(
const
bigint
&
other
)
{
bigits_
.
resize
(
other
.
bigits_
.
size
());
auto
size
=
other
.
bigits_
.
size
();
bigits_
.
resize
(
size
);
auto
data
=
other
.
bigits_
.
data
();
std
::
copy
(
data
,
data
+
other
.
bigits_
.
size
(),
bigits_
.
data
(
));
std
::
copy
(
data
,
data
+
size
,
make_checked
(
bigits_
.
data
(),
size
));
exp_
=
other
.
exp_
;
}
...
...
@@ -594,7 +622,7 @@ class bigint {
int
num_bigits
()
const
{
return
static_cast
<
int
>
(
bigits_
.
size
())
+
exp_
;
}
bigint
&
operator
<<=
(
int
shift
)
{
FMT_NOINLINE
bigint
&
operator
<<=
(
int
shift
)
{
assert
(
shift
>=
0
);
exp_
+=
shift
/
bigit_bits
;
shift
%=
bigit_bits
;
...
...
@@ -1125,7 +1153,7 @@ int snprintf_float(T value, int precision, float_specs specs,
precision
=
(
precision
>=
0
?
precision
:
6
)
-
1
;
// Build the format string.
enum
{
max_format_size
=
7
};
// Th
s
longest format is "%#.*Le".
enum
{
max_format_size
=
7
};
// Th
e
longest format is "%#.*Le".
char
format
[
max_format_size
];
char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
...
...
@@ -1145,13 +1173,13 @@ int snprintf_float(T value, int precision, float_specs specs,
for
(;;)
{
auto
begin
=
buf
.
data
()
+
offset
;
auto
capacity
=
buf
.
capacity
()
-
offset
;
#ifdef F
UZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#ifdef F
MT_FUZZ
if
(
precision
>
100000
)
throw
std
::
runtime_error
(
"fuzz mode - avoid large allocation inside snprintf"
);
#endif
// Suppress the warning about a nonliteral format string.
// Cannot use auto becase of a bug in MinGW (#1532).
// Cannot use auto beca
u
se of a bug in MinGW (#1532).
int
(
*
snprintf_ptr
)(
char
*
,
size_t
,
const
char
*
,
...)
=
FMT_SNPRINTF
;
int
result
=
precision
>=
0
?
snprintf_ptr
(
begin
,
capacity
,
format
,
precision
,
value
)
...
...
@@ -1268,14 +1296,14 @@ FMT_FUNC const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
return
next
;
}
}
// namespace
interna
l
}
// namespace
detai
l
template
<
>
struct
formatter
<
interna
l
::
bigint
>
{
template
<
>
struct
formatter
<
detai
l
::
bigint
>
{
format_parse_context
::
iterator
parse
(
format_parse_context
&
ctx
)
{
return
ctx
.
begin
();
}
format_context
::
iterator
format
(
const
interna
l
::
bigint
&
n
,
format_context
::
iterator
format
(
const
detai
l
::
bigint
&
n
,
format_context
&
ctx
)
{
auto
out
=
ctx
.
out
();
bool
first
=
true
;
...
...
@@ -1289,12 +1317,12 @@ template <> struct formatter<internal::bigint> {
out
=
format_to
(
out
,
"{:08x}"
,
value
);
}
if
(
n
.
exp_
>
0
)
out
=
format_to
(
out
,
"p{}"
,
n
.
exp_
*
interna
l
::
bigint
::
bigit_bits
);
out
=
format_to
(
out
,
"p{}"
,
n
.
exp_
*
detai
l
::
bigint
::
bigit_bits
);
return
out
;
}
};
FMT_FUNC
interna
l
::
utf8_to_utf16
::
utf8_to_utf16
(
string_view
s
)
{
FMT_FUNC
detai
l
::
utf8_to_utf16
::
utf8_to_utf16
(
string_view
s
)
{
auto
transcode
=
[
this
](
const
char
*
p
)
{
auto
cp
=
uint32_t
();
auto
error
=
0
;
...
...
@@ -1325,7 +1353,7 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
buffer_
.
push_back
(
0
);
}
FMT_FUNC
void
format_system_error
(
interna
l
::
buffer
<
char
>&
out
,
int
error_code
,
FMT_FUNC
void
format_system_error
(
detai
l
::
buffer
<
char
>&
out
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
memory_buffer
buf
;
...
...
@@ -1333,12 +1361,9 @@ FMT_FUNC void format_system_error(internal::buffer<char>& out, int error_code,
for
(;;)
{
char
*
system_message
=
&
buf
[
0
];
int
result
=
interna
l
::
safe_strerror
(
error_code
,
system_message
,
buf
.
size
());
detai
l
::
safe_strerror
(
error_code
,
system_message
,
buf
.
size
());
if
(
result
==
0
)
{
internal
::
writer
w
(
out
);
w
.
write
(
message
);
w
.
write
(
": "
);
w
.
write
(
system_message
);
format_to
(
std
::
back_inserter
(
out
),
"{}: {}"
,
message
,
system_message
);
return
;
}
if
(
result
!=
ERANGE
)
...
...
@@ -1350,7 +1375,7 @@ FMT_FUNC void format_system_error(internal::buffer<char>& out, int error_code,
format_error_code
(
out
,
error_code
,
message
);
}
FMT_FUNC
void
interna
l
::
error_handler
::
on_error
(
const
char
*
message
)
{
FMT_FUNC
void
detai
l
::
error_handler
::
on_error
(
const
char
*
message
)
{
FMT_THROW
(
format_error
(
message
));
}
...
...
@@ -1359,14 +1384,39 @@ FMT_FUNC void report_system_error(int error_code,
report_error
(
format_system_error
,
error_code
,
message
);
}
struct
stringifier
{
template
<
typename
T
>
FMT_INLINE
std
::
string
operator
()(
T
value
)
const
{
return
to_string
(
value
);
}
std
::
string
operator
()(
basic_format_arg
<
format_context
>::
handle
h
)
const
{
memory_buffer
buf
;
detail
::
buffer
<
char
>&
base
=
buf
;
format_parse_context
parse_ctx
({});
format_context
format_ctx
(
std
::
back_inserter
(
base
),
{},
{});
h
.
format
(
parse_ctx
,
format_ctx
);
return
to_string
(
buf
);
}
};
FMT_FUNC
std
::
string
detail
::
vformat
(
string_view
format_str
,
format_args
args
)
{
if
(
format_str
.
size
()
==
2
&&
equal2
(
format_str
.
data
(),
"{}"
))
{
auto
arg
=
args
.
get
(
0
);
if
(
!
arg
)
error_handler
().
on_error
(
"argument not found"
);
return
visit_format_arg
(
stringifier
(),
arg
);
}
memory_buffer
buffer
;
detail
::
vformat_to
(
buffer
,
format_str
,
args
);
return
to_string
(
buffer
);
}
FMT_FUNC
void
vprint
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
)
{
memory_buffer
buffer
;
interna
l
::
vformat_to
(
buffer
,
format_str
,
basic_format_args
<
buffer_context
<
char
>>
(
args
));
detai
l
::
vformat_to
(
buffer
,
format_str
,
basic_format_args
<
buffer_context
<
char
>>
(
args
));
#ifdef _WIN32
auto
fd
=
_fileno
(
f
);
if
(
_isatty
(
fd
))
{
interna
l
::
utf8_to_utf16
u16
(
string_view
(
buffer
.
data
(),
buffer
.
size
()));
detai
l
::
utf8_to_utf16
u16
(
string_view
(
buffer
.
data
(),
buffer
.
size
()));
auto
written
=
DWORD
();
if
(
!
WriteConsoleW
(
reinterpret_cast
<
HANDLE
>
(
_get_osfhandle
(
fd
)),
u16
.
c_str
(),
static_cast
<
DWORD
>
(
u16
.
size
()),
&
written
,
...
...
@@ -1376,16 +1426,16 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
return
;
}
#endif
interna
l
::
fwrite_fully
(
buffer
.
data
(),
1
,
buffer
.
size
(),
f
);
detai
l
::
fwrite_fully
(
buffer
.
data
(),
1
,
buffer
.
size
(),
f
);
}
#ifdef _WIN32
// Print assuming legacy (non-Unicode) encoding.
FMT_FUNC
void
interna
l
::
vprint_mojibake
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
)
{
FMT_FUNC
void
detai
l
::
vprint_mojibake
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
)
{
memory_buffer
buffer
;
interna
l
::
vformat_to
(
buffer
,
format_str
,
basic_format_args
<
buffer_context
<
char
>>
(
args
));
detai
l
::
vformat_to
(
buffer
,
format_str
,
basic_format_args
<
buffer_context
<
char
>>
(
args
));
fwrite_fully
(
buffer
.
data
(),
1
,
buffer
.
size
(),
f
);
}
#endif
...
...
include/spdlog/fmt/bundled/format.h
View file @
23c2c00d
This source diff could not be displayed because it is too large. You can
view the blob
instead.
include/spdlog/fmt/bundled/locale.h
View file @
23c2c00d
...
...
@@ -14,15 +14,15 @@
FMT_BEGIN_NAMESPACE
namespace
interna
l
{
namespace
detai
l
{
template
<
typename
Char
>
typename
buffer_context
<
Char
>::
iterator
vformat_to
(
const
std
::
locale
&
loc
,
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
using
range
=
buffer_range
<
Char
>
;
return
vformat_to
<
a
rg_formatter
<
range
>>
(
buf
,
to_string_view
(
format_str
),
args
,
interna
l
::
locale_ref
(
loc
));
using
af
=
arg_formatter
<
typename
buffer_context
<
Char
>::
iterator
,
Char
>
;
return
vformat_to
<
a
f
>
(
std
::
back_inserter
(
buf
),
to_string_view
(
format_str
)
,
args
,
detai
l
::
locale_ref
(
loc
));
}
template
<
typename
Char
>
...
...
@@ -30,43 +30,43 @@ std::basic_string<Char> vformat(
const
std
::
locale
&
loc
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
interna
l
::
vformat_to
(
loc
,
buffer
,
format_str
,
args
);
detai
l
::
vformat_to
(
loc
,
buffer
,
format_str
,
args
);
return
fmt
::
to_string
(
buffer
);
}
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
vformat
(
const
std
::
locale
&
loc
,
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
return
interna
l
::
vformat
(
loc
,
to_string_view
(
format_str
),
args
);
return
detai
l
::
vformat
(
loc
,
to_string_view
(
format_str
),
args
);
}
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
format
(
const
std
::
locale
&
loc
,
const
S
&
format_str
,
Args
&&
...
args
)
{
return
interna
l
::
vformat
(
return
detai
l
::
vformat
(
loc
,
to_string_view
(
format_str
),
interna
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
detai
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
}
template
<
typename
S
,
typename
OutputIt
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
interna
l
::
is_output_iterator
<
OutputIt
>
::
value
,
char_t
<
S
>>>
detai
l
::
is_output_iterator
<
OutputIt
>
::
value
,
char_t
<
S
>>>
inline
OutputIt
vformat_to
(
OutputIt
out
,
const
std
::
locale
&
loc
,
const
S
&
format_str
,
format_args_t
<
type_identity_t
<
OutputIt
>
,
Char
>
args
)
{
using
range
=
internal
::
output_range
<
OutputIt
,
Char
>
;
return
vformat_to
<
a
rg_formatter
<
range
>>
(
range
(
out
),
to_string_view
(
format_str
),
args
,
interna
l
::
locale_ref
(
loc
));
using
af
=
detail
::
arg_formatter
<
OutputIt
,
Char
>
;
return
vformat_to
<
a
f
>
(
out
,
to_string_view
(
format_str
),
args
,
detai
l
::
locale_ref
(
loc
));
}
template
<
typename
OutputIt
,
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
interna
l
::
is_output_iterator
<
OutputIt
>
::
value
&&
interna
l
::
is_string
<
S
>::
value
)
>
FMT_ENABLE_IF
(
detai
l
::
is_output_iterator
<
OutputIt
>
::
value
&&
detai
l
::
is_string
<
S
>::
value
)
>
inline
OutputIt
format_to
(
OutputIt
out
,
const
std
::
locale
&
loc
,
const
S
&
format_str
,
Args
&&
...
args
)
{
interna
l
::
check_format_string
<
Args
...
>
(
format_str
);
detai
l
::
check_format_string
<
Args
...
>
(
format_str
);
using
context
=
format_context_t
<
OutputIt
,
char_t
<
S
>>
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...};
return
vformat_to
(
out
,
loc
,
to_string_view
(
format_str
),
...
...
include/spdlog/fmt/bundled/ostream.h
View file @
23c2c00d
...
...
@@ -14,10 +14,10 @@
FMT_BEGIN_NAMESPACE
template
<
typename
C
H
ar
>
class
basic_printf_parse_context
;
template
<
typename
C
h
ar
>
class
basic_printf_parse_context
;
template
<
typename
OutputIt
,
typename
Char
>
class
basic_printf_context
;
namespace
interna
l
{
namespace
detai
l
{
template
<
class
Char
>
class
formatbuf
:
public
std
::
basic_streambuf
<
Char
>
{
private:
...
...
@@ -80,7 +80,7 @@ template <typename T, typename Char> class is_streamable {
// Write the content of buf to os.
template
<
typename
Char
>
void
write
(
std
::
basic_ostream
<
Char
>&
os
,
buffer
<
Char
>&
buf
)
{
void
write
_buffer
(
std
::
basic_ostream
<
Char
>&
os
,
buffer
<
Char
>&
buf
)
{
const
Char
*
buf_data
=
buf
.
data
();
using
unsigned_streamsize
=
std
::
make_unsigned
<
std
::
streamsize
>::
type
;
unsigned_streamsize
size
=
buf
.
size
();
...
...
@@ -101,8 +101,8 @@ void format_value(buffer<Char>& buf, const T& value,
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
if
(
loc
)
output
.
imbue
(
loc
.
get
<
std
::
locale
>
());
#endif
output
.
exceptions
(
std
::
ios_base
::
failbit
|
std
::
ios_base
::
badbit
);
output
<<
value
;
output
.
exceptions
(
std
::
ios_base
::
failbit
|
std
::
ios_base
::
badbit
);
buf
.
resize
(
buf
.
size
());
}
...
...
@@ -110,7 +110,8 @@ void format_value(buffer<Char>& buf, const T& value,
template
<
typename
T
,
typename
Char
>
struct
fallback_formatter
<
T
,
Char
,
enable_if_t
<
is_streamable
<
T
,
Char
>::
value
>>
:
private
formatter
<
basic_string_view
<
Char
>
,
Char
>
{
auto
parse
(
basic_format_parse_context
<
Char
>&
ctx
)
->
decltype
(
ctx
.
begin
())
{
FMT_CONSTEXPR
auto
parse
(
basic_format_parse_context
<
Char
>&
ctx
)
->
decltype
(
ctx
.
begin
())
{
return
formatter
<
basic_string_view
<
Char
>
,
Char
>::
parse
(
ctx
);
}
template
<
typename
ParseCtx
,
...
...
@@ -136,14 +137,14 @@ struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
return
std
::
copy
(
buffer
.
begin
(),
buffer
.
end
(),
ctx
.
out
());
}
};
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
Char
>
void
vprint
(
std
::
basic_ostream
<
Char
>&
os
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
type_identity_t
<
Char
>>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
interna
l
::
vformat_to
(
buffer
,
format_str
,
args
);
internal
::
write
(
os
,
buffer
);
detai
l
::
vformat_to
(
buffer
,
format_str
,
args
);
detail
::
write_buffer
(
os
,
buffer
);
}
/**
...
...
@@ -156,10 +157,10 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
\endrst
*/
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
interna
l
::
is_string
<
S
>
::
value
,
char_t
<
S
>>>
typename
Char
=
enable_if_t
<
detai
l
::
is_string
<
S
>
::
value
,
char_t
<
S
>>>
void
print
(
std
::
basic_ostream
<
Char
>&
os
,
const
S
&
format_str
,
Args
&&
...
args
)
{
vprint
(
os
,
to_string_view
(
format_str
),
interna
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
detai
l
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/posix.h
View file @
23c2c00d
#include "os.h"
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"
\ No newline at end of file
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"
include/spdlog/fmt/bundled/printf.h
View file @
23c2c00d
...
...
@@ -14,7 +14,7 @@
#include "ostream.h"
FMT_BEGIN_NAMESPACE
namespace
interna
l
{
namespace
detai
l
{
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
...
...
@@ -90,11 +90,11 @@ template <typename T, typename Context> class arg_converter {
if
(
const_check
(
sizeof
(
target_type
)
<=
sizeof
(
int
)))
{
// Extra casts are used to silence warnings.
if
(
is_signed
)
{
arg_
=
interna
l
::
make_arg
<
Context
>
(
arg_
=
detai
l
::
make_arg
<
Context
>
(
static_cast
<
int
>
(
static_cast
<
target_type
>
(
value
)));
}
else
{
using
unsigned_type
=
typename
make_unsigned_or_bool
<
target_type
>::
type
;
arg_
=
interna
l
::
make_arg
<
Context
>
(
arg_
=
detai
l
::
make_arg
<
Context
>
(
static_cast
<
unsigned
>
(
static_cast
<
unsigned_type
>
(
value
)));
}
}
else
{
...
...
@@ -102,9 +102,9 @@ template <typename T, typename Context> class arg_converter {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_
=
interna
l
::
make_arg
<
Context
>
(
static_cast
<
long
long
>
(
value
));
arg_
=
detai
l
::
make_arg
<
Context
>
(
static_cast
<
long
long
>
(
value
));
}
else
{
arg_
=
interna
l
::
make_arg
<
Context
>
(
arg_
=
detai
l
::
make_arg
<
Context
>
(
static_cast
<
typename
make_unsigned_or_bool
<
U
>::
type
>
(
value
));
}
}
...
...
@@ -133,7 +133,7 @@ template <typename Context> class char_converter {
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
void
operator
()(
T
value
)
{
arg_
=
interna
l
::
make_arg
<
Context
>
(
arg_
=
detai
l
::
make_arg
<
Context
>
(
static_cast
<
typename
Context
::
char_type
>
(
value
));
}
...
...
@@ -141,6 +141,13 @@ template <typename Context> class char_converter {
void
operator
()(
T
)
{}
// No conversion needed for non-integral types.
};
// An argument visitor that return a pointer to a C string if argument is a
// string or null otherwise.
template
<
typename
Char
>
struct
get_cstring
{
template
<
typename
T
>
const
Char
*
operator
()(
T
)
{
return
nullptr
;
}
const
Char
*
operator
()(
const
Char
*
s
)
{
return
s
;
}
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template
<
typename
Char
>
class
printf_width_handler
{
...
...
@@ -155,7 +162,7 @@ template <typename Char> class printf_width_handler {
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
unsigned
operator
()(
T
value
)
{
auto
width
=
static_cast
<
uint32_or_64_or_128_t
<
T
>>
(
value
);
if
(
interna
l
::
is_negative
(
value
))
{
if
(
detai
l
::
is_negative
(
value
))
{
specs_
.
align
=
align
::
left
;
width
=
0
-
width
;
}
...
...
@@ -172,22 +179,20 @@ template <typename Char> class printf_width_handler {
};
template
<
typename
Char
,
typename
Context
>
void
printf
(
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format
,
basic_format_args
<
Context
>
args
)
{
void
v
printf
(
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format
,
basic_format_args
<
Context
>
args
)
{
Context
(
std
::
back_inserter
(
buf
),
format
,
args
).
format
();
}
}
// namespace detail
template
<
typename
OutputIt
,
typename
Char
,
typename
Context
>
internal
::
truncating_iterator
<
OutputIt
>
printf
(
internal
::
truncating_iterator
<
OutputIt
>
it
,
basic_string_view
<
Char
>
format
,
basic_format_args
<
Context
>
args
)
{
return
Context
(
it
,
format
,
args
).
format
();
// For printing into memory_buffer.
template
<
typename
Char
,
typename
Context
>
FMT_DEPRECATED
void
printf
(
detail
::
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format
,
basic_format_args
<
Context
>
args
)
{
return
detail
::
vprintf
(
buf
,
format
,
args
);
}
}
// namespace internal
using
internal
::
printf
;
// For printing into memory_buffer.
template
<
typename
Range
>
class
printf_arg_formatter
;
using
detail
::
vprintf
;
template
<
typename
Char
>
class
basic_printf_parse_context
:
public
basic_format_parse_context
<
Char
>
{
...
...
@@ -200,15 +205,15 @@ template <typename OutputIt, typename Char> class basic_printf_context;
The ``printf`` argument formatter.
\endrst
*/
template
<
typename
Range
>
class
printf_arg_formatter
:
public
internal
::
arg_formatter_base
<
Range
>
{
template
<
typename
OutputIt
,
typename
Char
>
class
printf_arg_formatter
:
public
detail
::
arg_formatter_base
<
OutputIt
,
Char
>
{
public:
using
iterator
=
typename
Range
::
iterator
;
using
iterator
=
OutputIt
;
private:
using
char_type
=
typename
Range
::
value_type
;
using
base
=
internal
::
arg_formatter_base
<
Range
>
;
using
context_type
=
basic_printf_context
<
iterator
,
char_type
>
;
using
char_type
=
Char
;
using
base
=
detail
::
arg_formatter_base
<
OutputIt
,
Char
>
;
using
context_type
=
basic_printf_context
<
OutputIt
,
Char
>
;
context_type
&
context_
;
...
...
@@ -233,9 +238,9 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
\endrst
*/
printf_arg_formatter
(
iterator
iter
,
format_specs
&
specs
,
context_type
&
ctx
)
:
base
(
Range
(
iter
),
&
specs
,
interna
l
::
locale_ref
()),
context_
(
ctx
)
{}
:
base
(
iter
,
&
specs
,
detai
l
::
locale_ref
()),
context_
(
ctx
)
{}
template
<
typename
T
,
FMT_ENABLE_IF
(
fmt
::
interna
l
::
is_integral
<
T
>
::
value
)
>
template
<
typename
T
,
FMT_ENABLE_IF
(
fmt
::
detai
l
::
is_integral
<
T
>
::
value
)
>
iterator
operator
()(
T
value
)
{
// MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead.
...
...
@@ -250,7 +255,11 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
return
(
*
this
)(
static_cast
<
int
>
(
value
));
fmt_specs
.
sign
=
sign
::
none
;
fmt_specs
.
alt
=
false
;
fmt_specs
.
align
=
align
::
right
;
fmt_specs
.
fill
[
0
]
=
' '
;
// Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if
(
fmt_specs
.
align
==
align
::
none
||
fmt_specs
.
align
==
align
::
numeric
)
fmt_specs
.
align
=
align
::
right
;
return
base
::
operator
()(
value
);
}
else
{
return
base
::
operator
()(
value
);
...
...
@@ -316,12 +325,14 @@ template <typename T> struct printf_formatter {
template
<
typename
FormatContext
>
auto
format
(
const
T
&
value
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
internal
::
format_value
(
interna
l
::
get_container
(
ctx
.
out
()),
value
);
detail
::
format_value
(
detai
l
::
get_container
(
ctx
.
out
()),
value
);
return
ctx
.
out
();
}
};
/** This template formats data and writes the output to a writer. */
/**
This template formats data and writes the output through an output iterator.
*/
template
<
typename
OutputIt
,
typename
Char
>
class
basic_printf_context
{
public:
/** The character type for the output. */
...
...
@@ -351,9 +362,8 @@ template <typename OutputIt, typename Char> class basic_printf_context {
public:
/**
\rst
Constructs a ``printf_context`` object. References to the arguments and
the writer are stored in the context object so make sure they have
appropriate lifetimes.
Constructs a ``printf_context`` object. References to the arguments are
stored in the context object so make sure they have appropriate lifetimes.
\endrst
*/
basic_printf_context
(
OutputIt
out
,
basic_string_view
<
char_type
>
format_str
,
...
...
@@ -363,7 +373,7 @@ template <typename OutputIt, typename Char> class basic_printf_context {
OutputIt
out
()
{
return
out_
;
}
void
advance_to
(
OutputIt
it
)
{
out_
=
it
;
}
interna
l
::
locale_ref
locale
()
{
return
{};
}
detai
l
::
locale_ref
locale
()
{
return
{};
}
format_arg
arg
(
int
id
)
const
{
return
args_
.
get
(
id
);
}
...
...
@@ -374,7 +384,7 @@ template <typename OutputIt, typename Char> class basic_printf_context {
}
/** Formats stored arguments and writes the output to the range. */
template
<
typename
ArgFormatter
=
printf_arg_formatter
<
buffer_range
<
Char
>
>>
template
<
typename
ArgFormatter
=
printf_arg_formatter
<
OutputIt
,
Char
>
>
OutputIt
format
();
};
...
...
@@ -394,7 +404,9 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
specs
.
fill
[
0
]
=
'0'
;
break
;
case
' '
:
specs
.
sign
=
sign
::
space
;
if
(
specs
.
sign
!=
sign
::
plus
)
{
specs
.
sign
=
sign
::
space
;
}
break
;
case
'#'
:
specs
.
alt
=
true
;
...
...
@@ -412,7 +424,7 @@ basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
arg_index
=
parse_ctx_
.
next_arg_id
();
else
parse_ctx_
.
check_arg_id
(
--
arg_index
);
return
interna
l
::
get_arg
(
*
this
,
arg_index
);
return
detai
l
::
get_arg
(
*
this
,
arg_index
);
}
template
<
typename
OutputIt
,
typename
Char
>
...
...
@@ -424,7 +436,7 @@ int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
interna
l
::
error_handler
eh
;
detai
l
::
error_handler
eh
;
int
value
=
parse_nonnegative_int
(
it
,
end
,
eh
);
if
(
it
!=
end
&&
*
it
==
'$'
)
{
// value is an argument index
++
it
;
...
...
@@ -443,12 +455,12 @@ int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
// Parse width.
if
(
it
!=
end
)
{
if
(
*
it
>=
'0'
&&
*
it
<=
'9'
)
{
interna
l
::
error_handler
eh
;
detai
l
::
error_handler
eh
;
specs
.
width
=
parse_nonnegative_int
(
it
,
end
,
eh
);
}
else
if
(
*
it
==
'*'
)
{
++
it
;
specs
.
width
=
static_cast
<
int
>
(
visit_format_arg
(
interna
l
::
printf_width_handler
<
char_type
>
(
specs
),
get_arg
()));
detai
l
::
printf_width_handler
<
char_type
>
(
specs
),
get_arg
()));
}
}
return
arg_index
;
...
...
@@ -476,38 +488,52 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
// Parse argument index, flags and width.
int
arg_index
=
parse_header
(
it
,
end
,
specs
);
if
(
arg_index
==
0
)
on_error
(
"argument
index out of range
"
);
if
(
arg_index
==
0
)
on_error
(
"argument
not found
"
);
// Parse precision.
if
(
it
!=
end
&&
*
it
==
'.'
)
{
++
it
;
c
=
it
!=
end
?
*
it
:
0
;
if
(
'0'
<=
c
&&
c
<=
'9'
)
{
interna
l
::
error_handler
eh
;
detai
l
::
error_handler
eh
;
specs
.
precision
=
parse_nonnegative_int
(
it
,
end
,
eh
);
}
else
if
(
c
==
'*'
)
{
++
it
;
specs
.
precision
=
static_cast
<
int
>
(
visit_format_arg
(
interna
l
::
printf_precision_handler
(),
get_arg
()));
visit_format_arg
(
detai
l
::
printf_precision_handler
(),
get_arg
()));
}
else
{
specs
.
precision
=
0
;
}
}
format_arg
arg
=
get_arg
(
arg_index
);
if
(
specs
.
alt
&&
visit_format_arg
(
internal
::
is_zero_int
(),
arg
))
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if
(
specs
.
precision
>=
0
&&
arg
.
is_integral
())
specs
.
fill
[
0
]
=
' '
;
// Ignore '0' flag for non-numeric types or if '-' present.
if
(
specs
.
precision
>=
0
&&
arg
.
type
()
==
detail
::
type
::
cstring_type
)
{
auto
str
=
visit_format_arg
(
detail
::
get_cstring
<
Char
>
(),
arg
);
auto
str_end
=
str
+
specs
.
precision
;
auto
nul
=
std
::
find
(
str
,
str_end
,
Char
());
arg
=
detail
::
make_arg
<
basic_printf_context
>
(
basic_string_view
<
Char
>
(
str
,
detail
::
to_unsigned
(
nul
!=
str_end
?
nul
-
str
:
specs
.
precision
)));
}
if
(
specs
.
alt
&&
visit_format_arg
(
detail
::
is_zero_int
(),
arg
))
specs
.
alt
=
false
;
if
(
specs
.
fill
[
0
]
==
'0'
)
{
if
(
arg
.
is_arithmetic
())
if
(
arg
.
is_arithmetic
()
&&
specs
.
align
!=
align
::
left
)
specs
.
align
=
align
::
numeric
;
else
specs
.
fill
[
0
]
=
' '
;
// Ignore '0' flag for non-numeric types.
specs
.
fill
[
0
]
=
' '
;
// Ignore '0' flag for non-numeric types or if '-'
// flag is also present.
}
// Parse length and convert the argument to the required type.
c
=
it
!=
end
?
*
it
++
:
0
;
char_type
t
=
it
!=
end
?
*
it
:
0
;
using
interna
l
::
convert_arg
;
using
detai
l
::
convert_arg
;
switch
(
c
)
{
case
'h'
:
if
(
t
==
'h'
)
{
...
...
@@ -531,7 +557,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
convert_arg
<
intmax_t
>
(
arg
,
t
);
break
;
case
'z'
:
convert_arg
<
s
td
::
s
ize_t
>
(
arg
,
t
);
convert_arg
<
size_t
>
(
arg
,
t
);
break
;
case
't'
:
convert_arg
<
std
::
ptrdiff_t
>
(
arg
,
t
);
...
...
@@ -556,7 +582,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
specs
.
type
=
'd'
;
break
;
case
'c'
:
visit_format_arg
(
interna
l
::
char_converter
<
basic_printf_context
>
(
arg
),
visit_format_arg
(
detai
l
::
char_converter
<
basic_printf_context
>
(
arg
),
arg
);
break
;
}
...
...
@@ -565,15 +591,14 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
start
=
it
;
// Format argument.
visit_format_arg
(
ArgFormatter
(
out
,
specs
,
*
this
),
arg
);
out
=
visit_format_arg
(
ArgFormatter
(
out
,
specs
,
*
this
),
arg
);
}
return
std
::
copy
(
start
,
it
,
out
);
}
template
<
typename
Char
>
using
basic_printf_context_t
=
basic_printf_context
<
std
::
back_insert_iterator
<
internal
::
buffer
<
Char
>>
,
Char
>
;
basic_printf_context
<
std
::
back_insert_iterator
<
detail
::
buffer
<
Char
>>
,
Char
>
;
using
printf_context
=
basic_printf_context_t
<
char
>
;
using
wprintf_context
=
basic_printf_context_t
<
wchar_t
>
;
...
...
@@ -610,7 +635,7 @@ inline std::basic_string<Char> vsprintf(
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
type_identity_t
<
Char
>>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
printf
(
buffer
,
to_string_view
(
format
),
args
);
v
printf
(
buffer
,
to_string_view
(
format
),
args
);
return
to_string
(
buffer
);
}
...
...
@@ -624,7 +649,7 @@ inline std::basic_string<Char> vsprintf(
\endrst
*/
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
interna
l
::
is_string
<
S
>
::
value
,
char_t
<
S
>>>
typename
Char
=
enable_if_t
<
detai
l
::
is_string
<
S
>
::
value
,
char_t
<
S
>>>
inline
std
::
basic_string
<
Char
>
sprintf
(
const
S
&
format
,
const
Args
&
...
args
)
{
using
context
=
basic_printf_context_t
<
Char
>
;
return
vsprintf
(
to_string_view
(
format
),
make_format_args
<
context
>
(
args
...));
...
...
@@ -635,8 +660,8 @@ inline int vfprintf(
std
::
FILE
*
f
,
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
type_identity_t
<
Char
>>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
printf
(
buffer
,
to_string_view
(
format
),
args
);
s
td
::
s
ize_t
size
=
buffer
.
size
();
v
printf
(
buffer
,
to_string_view
(
format
),
args
);
size_t
size
=
buffer
.
size
();
return
std
::
fwrite
(
buffer
.
data
(),
sizeof
(
Char
),
size
,
f
)
<
size
?
-
1
:
static_cast
<
int
>
(
size
);
...
...
@@ -652,7 +677,7 @@ inline int vfprintf(
\endrst
*/
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
interna
l
::
is_string
<
S
>
::
value
,
char_t
<
S
>>>
typename
Char
=
enable_if_t
<
detai
l
::
is_string
<
S
>
::
value
,
char_t
<
S
>>>
inline
int
fprintf
(
std
::
FILE
*
f
,
const
S
&
format
,
const
Args
&
...
args
)
{
using
context
=
basic_printf_context_t
<
Char
>
;
return
vfprintf
(
f
,
to_string_view
(
format
),
...
...
@@ -676,7 +701,7 @@ inline int vprintf(
\endrst
*/
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
interna
l
::
is_string
<
S
>
::
value
)
>
FMT_ENABLE_IF
(
detai
l
::
is_string
<
S
>
::
value
)
>
inline
int
printf
(
const
S
&
format_str
,
const
Args
&
...
args
)
{
using
context
=
basic_printf_context_t
<
char_t
<
S
>>
;
return
vprintf
(
to_string_view
(
format_str
),
...
...
@@ -688,8 +713,8 @@ inline int vfprintf(
std
::
basic_ostream
<
Char
>&
os
,
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
type_identity_t
<
Char
>>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
printf
(
buffer
,
to_string_view
(
format
),
args
);
internal
::
write
(
os
,
buffer
);
v
printf
(
buffer
,
to_string_view
(
format
),
args
);
detail
::
write_buffer
(
os
,
buffer
);
return
static_cast
<
int
>
(
buffer
.
size
());
}
...
...
@@ -698,7 +723,7 @@ template <typename ArgFormatter, typename Char,
typename
Context
=
basic_printf_context
<
typename
ArgFormatter
::
iterator
,
Char
>
>
typename
ArgFormatter
::
iterator
vprintf
(
interna
l
::
buffer
<
Char
>&
out
,
basic_string_view
<
Char
>
format_str
,
detai
l
::
buffer
<
Char
>&
out
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
type_identity_t
<
Context
>>
args
)
{
typename
ArgFormatter
::
iterator
iter
(
out
);
Context
(
iter
,
format_str
,
args
).
template
format
<
ArgFormatter
>();
...
...
include/spdlog/fmt/bundled/ranges.h
View file @
23c2c00d
...
...
@@ -33,7 +33,7 @@ template <typename Char> struct formatting_base {
template
<
typename
Char
,
typename
Enable
=
void
>
struct
formatting_range
:
formatting_base
<
Char
>
{
static
FMT_CONSTEXPR_DECL
const
s
td
::
s
ize_t
range_length_limit
=
static
FMT_CONSTEXPR_DECL
const
size_t
range_length_limit
=
FMT_RANGE_OUTPUT_LENGTH_LIMIT
;
// output only up to N items from the
// range.
Char
prefix
;
...
...
@@ -54,7 +54,7 @@ struct formatting_tuple : formatting_base<Char> {
static
FMT_CONSTEXPR_DECL
const
bool
add_prepostfix_space
=
false
;
};
namespace
interna
l
{
namespace
detai
l
{
template
<
typename
RangeT
,
typename
OutputIterator
>
OutputIterator
copy
(
const
RangeT
&
range
,
OutputIterator
out
)
{
...
...
@@ -118,26 +118,24 @@ template <typename T> class is_tuple_like_ {
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template
<
typename
T
,
T
...
N
>
using
integer_sequence
=
std
::
integer_sequence
<
T
,
N
...
>
;
template
<
std
::
size_t
...
N
>
using
index_sequence
=
std
::
index_sequence
<
N
...
>
;
template
<
std
::
size_t
N
>
using
make_index_sequence
=
std
::
make_index_sequence
<
N
>
;
template
<
size_t
...
N
>
using
index_sequence
=
std
::
index_sequence
<
N
...
>
;
template
<
size_t
N
>
using
make_index_sequence
=
std
::
make_index_sequence
<
N
>
;
#else
template
<
typename
T
,
T
...
N
>
struct
integer_sequence
{
using
value_type
=
T
;
static
FMT_CONSTEXPR
s
td
::
s
ize_t
size
()
{
return
sizeof
...(
N
);
}
static
FMT_CONSTEXPR
size_t
size
()
{
return
sizeof
...(
N
);
}
};
template
<
std
::
size_t
...
N
>
using
index_sequence
=
integer_sequence
<
std
::
size_t
,
N
...
>
;
template
<
size_t
...
N
>
using
index_sequence
=
integer_sequence
<
size_t
,
N
...
>
;
template
<
typename
T
,
s
td
::
s
ize_t
N
,
T
...
Ns
>
template
<
typename
T
,
size_t
N
,
T
...
Ns
>
struct
make_integer_sequence
:
make_integer_sequence
<
T
,
N
-
1
,
N
-
1
,
Ns
...
>
{};
template
<
typename
T
,
T
...
Ns
>
struct
make_integer_sequence
<
T
,
0
,
Ns
...
>
:
integer_sequence
<
T
,
Ns
...
>
{};
template
<
s
td
::
s
ize_t
N
>
using
make_index_sequence
=
make_integer_sequence
<
s
td
::
s
ize_t
,
N
>
;
template
<
size_t
N
>
using
make_index_sequence
=
make_integer_sequence
<
size_t
,
N
>
;
#endif
template
<
class
Tuple
,
class
F
,
size_t
...
Is
>
...
...
@@ -185,11 +183,11 @@ FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return
add_space
?
L" '{}'"
:
L"'{}'"
;
}
}
// namespace
interna
l
}
// namespace
detai
l
template
<
typename
T
>
struct
is_tuple_like
{
static
FMT_CONSTEXPR_DECL
const
bool
value
=
internal
::
is_tuple_like_
<
T
>::
value
&&
!
interna
l
::
is_range_
<
T
>::
value
;
detail
::
is_tuple_like_
<
T
>::
value
&&
!
detai
l
::
is_range_
<
T
>::
value
;
};
template
<
typename
TupleT
,
typename
Char
>
...
...
@@ -202,17 +200,17 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
if
(
formatting
.
add_prepostfix_space
)
{
*
out
++
=
' '
;
}
out
=
interna
l
::
copy
(
formatting
.
delimiter
,
out
);
out
=
detai
l
::
copy
(
formatting
.
delimiter
,
out
);
}
out
=
format_to
(
out
,
interna
l
::
format_str_quoted
(
detai
l
::
format_str_quoted
(
(
formatting
.
add_delimiter_spaces
&&
i
>
0
),
v
),
v
);
++
i
;
}
formatting_tuple
<
Char
>&
formatting
;
s
td
::
s
ize_t
&
i
;
size_t
&
i
;
typename
std
::
add_lvalue_reference
<
decltype
(
std
::
declval
<
FormatContext
>
().
out
())
>::
type
out
;
};
...
...
@@ -228,14 +226,14 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
template
<
typename
FormatContext
=
format_context
>
auto
format
(
const
TupleT
&
values
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
out
=
ctx
.
out
();
s
td
::
s
ize_t
i
=
0
;
interna
l
::
copy
(
formatting
.
prefix
,
out
);
size_t
i
=
0
;
detai
l
::
copy
(
formatting
.
prefix
,
out
);
interna
l
::
for_each
(
values
,
format_each
<
FormatContext
>
{
formatting
,
i
,
out
});
detai
l
::
for_each
(
values
,
format_each
<
FormatContext
>
{
formatting
,
i
,
out
});
if
(
formatting
.
add_prepostfix_space
)
{
*
out
++
=
' '
;
}
interna
l
::
copy
(
formatting
.
postfix
,
out
);
detai
l
::
copy
(
formatting
.
postfix
,
out
);
return
ctx
.
out
();
}
...
...
@@ -243,10 +241,9 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
template
<
typename
T
,
typename
Char
>
struct
is_range
{
static
FMT_CONSTEXPR_DECL
const
bool
value
=
internal
::
is_range_
<
T
>::
value
&&
!
internal
::
is_like_std_string
<
T
>::
value
&&
detail
::
is_range_
<
T
>::
value
&&
!
detail
::
is_like_std_string
<
T
>::
value
&&
!
std
::
is_convertible
<
T
,
std
::
basic_string
<
Char
>>::
value
&&
!
std
::
is_constructible
<
interna
l
::
std_string_view
<
Char
>
,
T
>::
value
;
!
std
::
is_constructible
<
detai
l
::
std_string_view
<
Char
>
,
T
>::
value
;
};
template
<
typename
RangeT
,
typename
Char
>
...
...
@@ -262,15 +259,17 @@ struct formatter<RangeT, Char,
template
<
typename
FormatContext
>
typename
FormatContext
::
iterator
format
(
const
RangeT
&
values
,
FormatContext
&
ctx
)
{
auto
out
=
internal
::
copy
(
formatting
.
prefix
,
ctx
.
out
());
std
::
size_t
i
=
0
;
for
(
auto
it
=
values
.
begin
(),
end
=
values
.
end
();
it
!=
end
;
++
it
)
{
auto
out
=
detail
::
copy
(
formatting
.
prefix
,
ctx
.
out
());
size_t
i
=
0
;
auto
it
=
values
.
begin
();
auto
end
=
values
.
end
();
for
(;
it
!=
end
;
++
it
)
{
if
(
i
>
0
)
{
if
(
formatting
.
add_prepostfix_space
)
*
out
++
=
' '
;
out
=
interna
l
::
copy
(
formatting
.
delimiter
,
out
);
out
=
detai
l
::
copy
(
formatting
.
delimiter
,
out
);
}
out
=
format_to
(
out
,
interna
l
::
format_str_quoted
(
detai
l
::
format_str_quoted
(
(
formatting
.
add_delimiter_spaces
&&
i
>
0
),
*
it
),
*
it
);
if
(
++
i
>
formatting
.
range_length_limit
)
{
...
...
@@ -279,11 +278,11 @@ struct formatter<RangeT, Char,
}
}
if
(
formatting
.
add_prepostfix_space
)
*
out
++
=
' '
;
return
interna
l
::
copy
(
formatting
.
postfix
,
out
);
return
detai
l
::
copy
(
formatting
.
postfix
,
out
);
}
};
template
<
typename
Char
,
typename
...
T
>
struct
tuple_arg_join
:
interna
l
::
view
{
template
<
typename
Char
,
typename
...
T
>
struct
tuple_arg_join
:
detai
l
::
view
{
const
std
::
tuple
<
T
...
>&
tuple
;
basic_string_view
<
Char
>
sep
;
...
...
@@ -301,14 +300,14 @@ struct formatter<tuple_arg_join<Char, T...>, Char> {
template
<
typename
FormatContext
>
typename
FormatContext
::
iterator
format
(
const
tuple_arg_join
<
Char
,
T
...
>&
value
,
FormatContext
&
ctx
)
{
return
format
(
value
,
ctx
,
interna
l
::
make_index_sequence
<
sizeof
...(
T
)
>
{});
return
format
(
value
,
ctx
,
detai
l
::
make_index_sequence
<
sizeof
...(
T
)
>
{});
}
private:
template
<
typename
FormatContext
,
size_t
...
N
>
typename
FormatContext
::
iterator
format
(
const
tuple_arg_join
<
Char
,
T
...
>&
value
,
FormatContext
&
ctx
,
interna
l
::
index_sequence
<
N
...
>
)
{
detai
l
::
index_sequence
<
N
...
>
)
{
return
format_args
(
value
,
ctx
,
std
::
get
<
N
>
(
value
.
tuple
)...);
}
...
...
@@ -371,14 +370,14 @@ FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
\endrst
*/
template
<
typename
T
>
arg_join
<
internal
::
iterator_t
<
const
std
::
initializer_list
<
T
>>
,
char
>
join
(
std
::
initializer_list
<
T
>
list
,
string_view
sep
)
{
arg_join
<
const
T
*
,
const
T
*
,
char
>
join
(
std
::
initializer_list
<
T
>
list
,
string_view
sep
)
{
return
join
(
std
::
begin
(
list
),
std
::
end
(
list
),
sep
);
}
template
<
typename
T
>
arg_join
<
internal
::
iterator_t
<
const
std
::
initializer_list
<
T
>>
,
wchar_t
>
join
(
std
::
initializer_list
<
T
>
list
,
wstring_view
sep
)
{
arg_join
<
const
T
*
,
const
T
*
,
wchar_t
>
join
(
std
::
initializer_list
<
T
>
list
,
wstring_view
sep
)
{
return
join
(
std
::
begin
(
list
),
std
::
end
(
list
),
sep
);
}
...
...
src/fmt.cpp
View file @
23c2c00d
...
...
@@ -10,12 +10,12 @@
#include <spdlog/fmt/bundled/format-inl.h>
FMT_BEGIN_NAMESPACE
namespace
interna
l
{
namespace
detai
l
{
template
<
typename
T
>
int
format_float
(
char
*
buf
,
std
::
size_t
size
,
const
char
*
format
,
int
precision
,
T
value
)
{
#ifdef F
UZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#ifdef F
MT_FUZZ
if
(
precision
>
100000
)
throw
std
::
runtime_error
(
"fuzz mode - avoid large allocation inside snprintf"
);
#endif
...
...
@@ -23,167 +23,41 @@ int format_float(char *buf, std::size_t size, const char *format, int precision,
int
(
*
snprintf_ptr
)(
char
*
,
size_t
,
const
char
*
,
...)
=
FMT_SNPRINTF
;
return
precision
<
0
?
snprintf_ptr
(
buf
,
size
,
format
,
value
)
:
snprintf_ptr
(
buf
,
size
,
format
,
precision
,
value
);
}
struct
sprintf_specs
{
int
precision
;
char
type
;
bool
alt
:
1
;
template
<
typename
Char
>
constexpr
sprintf_specs
(
basic_format_specs
<
Char
>
specs
)
:
precision
(
specs
.
precision
)
,
type
(
specs
.
type
)
,
alt
(
specs
.
alt
)
{}
constexpr
bool
has_precision
()
const
{
return
precision
>=
0
;
}
};
// This is deprecated and is kept only to preserve ABI compatibility.
template
<
typename
Double
>
char
*
sprintf_format
(
Double
value
,
internal
::
buffer
<
char
>
&
buf
,
sprintf_specs
specs
)
{
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT
(
buf
.
capacity
()
!=
0
,
"empty buffer"
);
// Build format string.
enum
{
max_format_size
=
10
};
// longest format: %#-*.*Lg
char
format
[
max_format_size
];
char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
if
(
specs
.
alt
||
!
specs
.
type
)
*
format_ptr
++
=
'#'
;
if
(
specs
.
precision
>=
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
}
if
(
std
::
is_same
<
Double
,
long
double
>::
value
)
*
format_ptr
++
=
'L'
;
char
type
=
specs
.
type
;
if
(
type
==
'%'
)
type
=
'f'
;
else
if
(
type
==
0
||
type
==
'n'
)
type
=
'g'
;
#if FMT_MSC_VER
if
(
type
==
'F'
)
{
// MSVC's printf doesn't support 'F'.
type
=
'f'
;
}
#endif
*
format_ptr
++
=
type
;
*
format_ptr
=
'\0'
;
// Format using snprintf.
char
*
start
=
nullptr
;
char
*
decimal_point_pos
=
nullptr
;
for
(;;)
{
std
::
size_t
buffer_size
=
buf
.
capacity
();
start
=
&
buf
[
0
];
int
result
=
format_float
(
start
,
buffer_size
,
format
,
specs
.
precision
,
value
);
if
(
result
>=
0
)
{
unsigned
n
=
internal
::
to_unsigned
(
result
);
if
(
n
<
buf
.
capacity
())
{
// Find the decimal point.
auto
p
=
buf
.
data
(),
end
=
p
+
n
;
if
(
*
p
==
'+'
||
*
p
==
'-'
)
++
p
;
if
(
specs
.
type
!=
'a'
&&
specs
.
type
!=
'A'
)
{
while
(
p
<
end
&&
*
p
>=
'0'
&&
*
p
<=
'9'
)
++
p
;
if
(
p
<
end
&&
*
p
!=
'e'
&&
*
p
!=
'E'
)
{
decimal_point_pos
=
p
;
if
(
!
specs
.
type
)
{
// Keep only one trailing zero after the decimal point.
++
p
;
if
(
*
p
==
'0'
)
++
p
;
while
(
p
!=
end
&&
*
p
>=
'1'
&&
*
p
<=
'9'
)
++
p
;
char
*
where
=
p
;
while
(
p
!=
end
&&
*
p
==
'0'
)
++
p
;
if
(
p
==
end
||
*
p
<
'0'
||
*
p
>
'9'
)
{
if
(
p
!=
end
)
std
::
memmove
(
where
,
p
,
to_unsigned
(
end
-
p
));
n
-=
static_cast
<
unsigned
>
(
p
-
where
);
}
}
}
}
buf
.
resize
(
n
);
break
;
// The buffer is large enough - continue with formatting.
}
buf
.
reserve
(
n
+
1
);
}
else
{
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buf
.
reserve
(
buf
.
capacity
()
+
1
);
}
}
return
decimal_point_pos
;
}
}
// namespace internal
}
// namespace detail
template
FMT_API
char
*
internal
::
sprintf_format
(
double
,
internal
::
buffer
<
char
>
&
,
sprintf_specs
);
template
FMT_API
char
*
internal
::
sprintf_format
(
long
double
,
internal
::
buffer
<
char
>
&
,
sprintf_specs
);
template
struct
FMT_INSTANTIATION_DEF_API
internal
::
basic_data
<
void
>;
template
struct
FMT_INSTANTIATION_DEF_API
detail
::
basic_data
<
void
>;
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
int
(
*
instantiate_format_float
)(
double
,
int
,
internal
::
float_specs
,
internal
::
buffer
<
char
>
&
)
=
interna
l
::
format_float
;
int
(
*
instantiate_format_float
)(
double
,
int
,
detail
::
float_specs
,
detail
::
buffer
<
char
>
&
)
=
detai
l
::
format_float
;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template
FMT_API
interna
l
::
locale_ref
::
locale_ref
(
const
std
::
locale
&
loc
);
template
FMT_API
std
::
locale
interna
l
::
locale_ref
::
get
<
std
::
locale
>()
const
;
template
FMT_API
detai
l
::
locale_ref
::
locale_ref
(
const
std
::
locale
&
loc
);
template
FMT_API
std
::
locale
detai
l
::
locale_ref
::
get
<
std
::
locale
>()
const
;
#endif
// Explicit instantiations for char.
template
FMT_API
std
::
string
internal
::
grouping_impl
<
char
>(
locale_ref
);
template
FMT_API
char
internal
::
thousands_sep_impl
(
locale_ref
);
template
FMT_API
char
internal
::
decimal_point_impl
(
locale_ref
);
template
FMT_API
void
internal
::
buffer
<
char
>
::
append
(
const
char
*
,
const
char
*
);
template
FMT_API
std
::
string
detail
::
grouping_impl
<
char
>(
locale_ref
);
template
FMT_API
char
detail
::
thousands_sep_impl
(
locale_ref
);
template
FMT_API
char
detail
::
decimal_point_impl
(
locale_ref
);
template
FMT_API
void
internal
::
arg_map
<
format_context
>
::
init
(
const
basic_format_args
<
format_context
>
&
args
);
template
FMT_API
void
detail
::
buffer
<
char
>
::
append
(
const
char
*
,
const
char
*
);
template
FMT_API
std
::
string
internal
::
vformat
<
char
>(
string_view
,
basic_format_args
<
format_context
>);
template
FMT_API
FMT_BUFFER_CONTEXT
(
char
)
::
iterator
detail
::
vformat_to
(
detail
::
buffer
<
char
>
&
,
string_view
,
basic_format_args
<
FMT_BUFFER_CONTEXT
(
char
)
>
);
template
FMT_API
format_context
::
iterator
internal
::
vformat_to
(
internal
::
buffer
<
char
>
&
,
string_view
,
basic_format_args
<
format_context
>);
template
FMT_API
int
internal
::
snprintf_float
(
double
,
int
,
internal
::
float_specs
,
internal
::
buffer
<
char
>
&
);
template
FMT_API
int
internal
::
snprintf_float
(
long
double
,
int
,
internal
::
float_specs
,
internal
::
buffer
<
char
>
&
);
template
FMT_API
int
internal
::
format_float
(
double
,
int
,
internal
::
float_specs
,
internal
::
buffer
<
char
>
&
);
template
FMT_API
int
internal
::
format_float
(
long
double
,
int
,
internal
::
float_specs
,
internal
::
buffer
<
char
>
&
);
template
FMT_API
int
detail
::
snprintf_float
(
double
,
int
,
detail
::
float_specs
,
detail
::
buffer
<
char
>
&
);
template
FMT_API
int
detail
::
snprintf_float
(
long
double
,
int
,
detail
::
float_specs
,
detail
::
buffer
<
char
>
&
);
template
FMT_API
int
detail
::
format_float
(
double
,
int
,
detail
::
float_specs
,
detail
::
buffer
<
char
>
&
);
template
FMT_API
int
detail
::
format_float
(
long
double
,
int
,
detail
::
float_specs
,
detail
::
buffer
<
char
>
&
);
// Explicit instantiations for wchar_t.
template
FMT_API
std
::
string
internal
::
grouping_impl
<
wchar_t
>(
locale_ref
);
template
FMT_API
wchar_t
internal
::
thousands_sep_impl
(
locale_ref
);
template
FMT_API
wchar_t
internal
::
decimal_point_impl
(
locale_ref
);
template
FMT_API
void
internal
::
buffer
<
wchar_t
>
::
append
(
const
wchar_t
*
,
const
wchar_t
*
);
template
FMT_API
std
::
string
detail
::
grouping_impl
<
wchar_t
>(
locale_ref
);
template
FMT_API
wchar_t
detail
::
thousands_sep_impl
(
locale_ref
);
template
FMT_API
wchar_t
detail
::
decimal_point_impl
(
locale_ref
);
template
FMT_API
std
::
wstring
internal
::
vformat
<
wchar_t
>(
wstring_view
,
basic_format_args
<
wformat_context
>
);
template
FMT_API
void
detail
::
buffer
<
wchar_t
>
::
append
(
const
wchar_t
*
,
const
wchar_t
*
);
FMT_END_NAMESPACE
#endif // !SPDLOG_FMT_EXTERNAL
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment