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
e149433a
Commit
e149433a
authored
Sep 06, 2019
by
Tobias Pfeiffer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bumped fmt to version 6.0.0
parent
65d02e49
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
5518 additions
and
4735 deletions
+5518
-4735
include/spdlog/fmt/bundled/LICENSE.rst
include/spdlog/fmt/bundled/LICENSE.rst
+23
-19
include/spdlog/fmt/bundled/chrono.h
include/spdlog/fmt/bundled/chrono.h
+521
-144
include/spdlog/fmt/bundled/color.h
include/spdlog/fmt/bundled/color.h
+296
-288
include/spdlog/fmt/bundled/compile.h
include/spdlog/fmt/bundled/compile.h
+466
-0
include/spdlog/fmt/bundled/core.h
include/spdlog/fmt/bundled/core.h
+806
-894
include/spdlog/fmt/bundled/format-inl.h
include/spdlog/fmt/bundled/format-inl.h
+531
-503
include/spdlog/fmt/bundled/format.h
include/spdlog/fmt/bundled/format.h
+2043
-1998
include/spdlog/fmt/bundled/locale.h
include/spdlog/fmt/bundled/locale.h
+33
-33
include/spdlog/fmt/bundled/ostream.h
include/spdlog/fmt/bundled/ostream.h
+41
-58
include/spdlog/fmt/bundled/posix.h
include/spdlog/fmt/bundled/posix.h
+65
-78
include/spdlog/fmt/bundled/printf.h
include/spdlog/fmt/bundled/printf.h
+313
-453
include/spdlog/fmt/bundled/ranges.h
include/spdlog/fmt/bundled/ranges.h
+87
-107
include/spdlog/fmt/bundled/safe-duration-cast.h
include/spdlog/fmt/bundled/safe-duration-cast.h
+293
-0
include/spdlog/fmt/bundled/time.h
include/spdlog/fmt/bundled/time.h
+0
-160
No files found.
include/spdlog/fmt/bundled/LICENSE.rst
View file @
e149433a
Copyright (c) 2012 -
2016
, Victor Zverovich
Copyright (c) 2012 -
present
, Victor Zverovich
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- Optional exception to the license ---
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into a machine-executable object form of such
source code, you may redistribute such embedded portions in such object form
without including the above copyright and permission notices.
include/spdlog/fmt/bundled/chrono.h
View file @
e149433a
...
...
@@ -16,9 +16,181 @@
#include <locale>
#include <sstream>
// enable safe chrono durations, unless explicitly disabled
#ifndef FMT_SAFE_DURATION_CAST
# define FMT_SAFE_DURATION_CAST 1
#endif
#if FMT_SAFE_DURATION_CAST
# include "safe-duration-cast.h"
#endif
FMT_BEGIN_NAMESPACE
namespace
internal
{
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
namespace
internal
{
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 internal
// Thread-safe replacement for std::localtime
inline
std
::
tm
localtime
(
std
::
time_t
time
)
{
struct
dispatcher
{
std
::
time_t
time_
;
std
::
tm
tm_
;
dispatcher
(
std
::
time_t
t
)
:
time_
(
t
)
{}
bool
run
()
{
using
namespace
fmt
::
internal
;
return
handle
(
localtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
nullptr
;
}
bool
handle
(
internal
::
null
<>
)
{
using
namespace
fmt
::
internal
;
return
fallback
(
localtime_s
(
&
tm_
,
&
time_
));
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
#if !FMT_MSC_VER
bool
fallback
(
internal
::
null
<>
)
{
using
namespace
fmt
::
internal
;
std
::
tm
*
tm
=
std
::
localtime
(
&
time_
);
if
(
tm
)
tm_
=
*
tm
;
return
tm
!=
nullptr
;
}
#endif
};
dispatcher
lt
(
time
);
// Too big time values may be unsupported.
if
(
!
lt
.
run
())
FMT_THROW
(
format_error
(
"time_t value out of range"
));
return
lt
.
tm_
;
}
// Thread-safe replacement for std::gmtime
inline
std
::
tm
gmtime
(
std
::
time_t
time
)
{
struct
dispatcher
{
std
::
time_t
time_
;
std
::
tm
tm_
;
dispatcher
(
std
::
time_t
t
)
:
time_
(
t
)
{}
bool
run
()
{
using
namespace
fmt
::
internal
;
return
handle
(
gmtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
nullptr
;
}
bool
handle
(
internal
::
null
<>
)
{
using
namespace
fmt
::
internal
;
return
fallback
(
gmtime_s
(
&
tm_
,
&
time_
));
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
#if !FMT_MSC_VER
bool
fallback
(
internal
::
null
<>
)
{
std
::
tm
*
tm
=
std
::
gmtime
(
&
time_
);
if
(
tm
)
tm_
=
*
tm
;
return
tm
!=
nullptr
;
}
#endif
};
dispatcher
gt
(
time
);
// Too big time values may be unsupported.
if
(
!
gt
.
run
())
FMT_THROW
(
format_error
(
"time_t value out of range"
));
return
gt
.
tm_
;
}
namespace
internal
{
inline
std
::
size_t
strftime
(
char
*
str
,
std
::
size_t
count
,
const
char
*
format
,
const
std
::
tm
*
time
)
{
return
std
::
strftime
(
str
,
count
,
format
,
time
);
}
inline
std
::
size_t
strftime
(
wchar_t
*
str
,
std
::
size_t
count
,
const
wchar_t
*
format
,
const
std
::
tm
*
time
)
{
return
std
::
wcsftime
(
str
,
count
,
format
,
time
);
}
}
// namespace internal
template
<
typename
Char
>
struct
formatter
<
std
::
tm
,
Char
>
{
template
<
typename
ParseContext
>
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
auto
it
=
ctx
.
begin
();
if
(
it
!=
ctx
.
end
()
&&
*
it
==
':'
)
++
it
;
auto
end
=
it
;
while
(
end
!=
ctx
.
end
()
&&
*
end
!=
'}'
)
++
end
;
tm_format
.
reserve
(
internal
::
to_unsigned
(
end
-
it
+
1
));
tm_format
.
append
(
it
,
end
);
tm_format
.
push_back
(
'\0'
);
return
end
;
}
template
<
typename
FormatContext
>
auto
format
(
const
std
::
tm
&
tm
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
basic_memory_buffer
<
Char
>
buf
;
std
::
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
);
if
(
count
!=
0
)
{
buf
.
resize
(
start
+
count
);
break
;
}
if
(
size
>=
tm_format
.
size
()
*
256
)
{
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break
;
}
const
std
::
size_t
MIN_GROWTH
=
10
;
buf
.
reserve
(
buf
.
capacity
()
+
(
size
>
MIN_GROWTH
?
size
:
MIN_GROWTH
));
}
return
std
::
copy
(
buf
.
begin
(),
buf
.
end
(),
ctx
.
out
());
}
basic_memory_buffer
<
Char
>
tm_format
;
};
namespace
internal
{
template
<
typename
Period
>
FMT_CONSTEXPR
const
char
*
get_units
()
{
return
nullptr
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
atto
>
()
{
return
"as"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
femto
>
()
{
return
"fs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
pico
>
()
{
return
"ps"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
nano
>
()
{
return
"ns"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
micro
>
()
{
return
"µs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
milli
>
()
{
return
"ms"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
centi
>
()
{
return
"cs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
deci
>
()
{
return
"ds"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
ratio
<
1
>>
()
{
return
"s"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
deca
>
()
{
return
"das"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
hecto
>
()
{
return
"hs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
kilo
>
()
{
return
"ks"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
mega
>
()
{
return
"Ms"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
giga
>
()
{
return
"Gs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
tera
>
()
{
return
"Ts"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
peta
>
()
{
return
"Ps"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
exa
>
()
{
return
"Es"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
ratio
<
60
>>
()
{
return
"m"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
ratio
<
3600
>>
()
{
return
"h"
;
}
enum
class
numeric_system
{
standard
,
...
...
@@ -28,8 +200,9 @@ enum class numeric_system {
// Parses a put_time-like format string and invokes handler actions.
template
<
typename
Char
,
typename
Handler
>
FMT_CONSTEXPR
const
Char
*
parse_chrono_format
(
const
Char
*
begin
,
const
Char
*
end
,
Handler
&&
handler
)
{
FMT_CONSTEXPR
const
Char
*
parse_chrono_format
(
const
Char
*
begin
,
const
Char
*
end
,
Handler
&&
handler
)
{
auto
ptr
=
begin
;
while
(
ptr
!=
end
)
{
auto
c
=
*
ptr
;
...
...
@@ -38,11 +211,9 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
++
ptr
;
continue
;
}
if
(
begin
!=
ptr
)
handler
.
on_text
(
begin
,
ptr
);
if
(
begin
!=
ptr
)
handler
.
on_text
(
begin
,
ptr
);
++
ptr
;
// consume '%'
if
(
ptr
==
end
)
throw
format_error
(
"invalid format"
);
if
(
ptr
==
end
)
FMT_THROW
(
format_error
(
"invalid format"
));
c
=
*
ptr
++
;
switch
(
c
)
{
case
'%'
:
...
...
@@ -119,6 +290,12 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
case
'p'
:
handler
.
on_am_pm
();
break
;
case
'Q'
:
handler
.
on_duration_value
();
break
;
case
'q'
:
handler
.
on_duration_unit
();
break
;
case
'z'
:
handler
.
on_utc_offset
();
break
;
...
...
@@ -127,8 +304,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
break
;
// Alternative representation:
case
'E'
:
{
if
(
ptr
==
end
)
throw
format_error
(
"invalid format"
);
if
(
ptr
==
end
)
FMT_THROW
(
format_error
(
"invalid format"
));
c
=
*
ptr
++
;
switch
(
c
)
{
case
'c'
:
...
...
@@ -141,13 +317,12 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
handler
.
on_loc_time
(
numeric_system
::
alternative
);
break
;
default:
throw
format_error
(
"invalid format"
);
FMT_THROW
(
format_error
(
"invalid format"
)
);
}
break
;
}
case
'O'
:
if
(
ptr
==
end
)
throw
format_error
(
"invalid format"
);
if
(
ptr
==
end
)
FMT_THROW
(
format_error
(
"invalid format"
));
c
=
*
ptr
++
;
switch
(
c
)
{
case
'w'
:
...
...
@@ -169,96 +344,259 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
handler
.
on_second
(
numeric_system
::
alternative
);
break
;
default:
throw
format_error
(
"invalid format"
);
FMT_THROW
(
format_error
(
"invalid format"
)
);
}
break
;
default:
throw
format_error
(
"invalid format"
);
FMT_THROW
(
format_error
(
"invalid format"
)
);
}
begin
=
ptr
;
}
if
(
begin
!=
ptr
)
handler
.
on_text
(
begin
,
ptr
);
if
(
begin
!=
ptr
)
handler
.
on_text
(
begin
,
ptr
);
return
ptr
;
}
struct
chrono_format_checker
{
void
report_no_date
()
{
throw
format_error
(
"no date"
);
}
template
<
typename
Char
>
void
on_text
(
const
Char
*
,
const
Char
*
)
{}
void
on_abbr_weekday
()
{
report_no_date
();
}
void
on_full_weekday
()
{
report_no_date
();
}
void
on_dec0_weekday
(
numeric_system
)
{
report_no_date
();
}
void
on_dec1_weekday
(
numeric_system
)
{
report_no_date
();
}
void
on_abbr_month
()
{
report_no_date
();
}
void
on_full_month
()
{
report_no_date
();
}
FMT_NORETURN
void
report_no_date
()
{
FMT_THROW
(
format_error
(
"no date"
));
}
template
<
typename
Char
>
void
on_text
(
const
Char
*
,
const
Char
*
)
{}
FMT_NORETURN
void
on_abbr_weekday
()
{
report_no_date
();
}
FMT_NORETURN
void
on_full_weekday
()
{
report_no_date
();
}
FMT_NORETURN
void
on_dec0_weekday
(
numeric_system
)
{
report_no_date
();
}
FMT_NORETURN
void
on_dec1_weekday
(
numeric_system
)
{
report_no_date
();
}
FMT_NORETURN
void
on_abbr_month
()
{
report_no_date
();
}
FMT_NORETURN
void
on_full_month
()
{
report_no_date
();
}
void
on_24_hour
(
numeric_system
)
{}
void
on_12_hour
(
numeric_system
)
{}
void
on_minute
(
numeric_system
)
{}
void
on_second
(
numeric_system
)
{}
void
on_datetime
(
numeric_system
)
{
report_no_date
();
}
void
on_loc_date
(
numeric_system
)
{
report_no_date
();
}
void
on_loc_time
(
numeric_system
)
{
report_no_date
();
}
void
on_us_date
()
{
report_no_date
();
}
void
on_iso_date
()
{
report_no_date
();
}
FMT_NORETURN
void
on_datetime
(
numeric_system
)
{
report_no_date
();
}
FMT_NORETURN
void
on_loc_date
(
numeric_system
)
{
report_no_date
();
}
FMT_NORETURN
void
on_loc_time
(
numeric_system
)
{
report_no_date
();
}
FMT_NORETURN
void
on_us_date
()
{
report_no_date
();
}
FMT_NORETURN
void
on_iso_date
()
{
report_no_date
();
}
void
on_12_hour_time
()
{}
void
on_24_hour_time
()
{}
void
on_iso_time
()
{}
void
on_am_pm
()
{}
void
on_utc_offset
()
{
report_no_date
();
}
void
on_tz_name
()
{
report_no_date
();
}
void
on_duration_value
()
{}
void
on_duration_unit
()
{}
FMT_NORETURN
void
on_utc_offset
()
{
report_no_date
();
}
FMT_NORETURN
void
on_tz_name
()
{
report_no_date
();
}
};
template
<
typename
Int
>
inline
int
to_int
(
Int
value
)
{
FMT_ASSERT
(
value
>=
(
std
::
numeric_limits
<
int
>::
min
)()
&&
value
<=
(
std
::
numeric_limits
<
int
>::
max
)(),
"invalid value"
);
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
inline
bool
isnan
(
T
)
{
return
false
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
T
>
::
value
)
>
inline
bool
isnan
(
T
value
)
{
return
std
::
isnan
(
value
);
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
inline
bool
isfinite
(
T
)
{
return
true
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
T
>
::
value
)
>
inline
bool
isfinite
(
T
value
)
{
return
std
::
isfinite
(
value
);
}
// Convers value to int and checks that it's in the range [0, upper).
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
inline
int
to_nonnegative_int
(
T
value
,
int
upper
)
{
FMT_ASSERT
(
value
>=
0
&&
value
<=
upper
,
"invalid value"
);
(
void
)
upper
;
return
static_cast
<
int
>
(
value
);
}
template
<
typename
T
,
FMT_ENABLE_IF
(
!
std
::
is_integral
<
T
>
::
value
)
>
inline
int
to_nonnegative_int
(
T
value
,
int
upper
)
{
FMT_ASSERT
(
std
::
isnan
(
value
)
||
(
value
>=
0
&&
value
<=
static_cast
<
T
>
(
upper
)),
"invalid value"
);
(
void
)
upper
;
return
static_cast
<
int
>
(
value
);
}
template
<
typename
FormatContext
,
typename
OutputIt
>
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
inline
T
mod
(
T
x
,
int
y
)
{
return
x
%
y
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
T
>
::
value
)
>
inline
T
mod
(
T
x
,
int
y
)
{
return
std
::
fmod
(
x
,
static_cast
<
T
>
(
y
));
}
// If T is an integral type, maps T to its unsigned counterpart, otherwise
// leaves it unchanged (unlike std::make_unsigned).
template
<
typename
T
,
bool
INTEGRAL
=
std
::
is_integral
<
T
>
::
value
>
struct
make_unsigned_or_unchanged
{
using
type
=
T
;
};
template
<
typename
T
>
struct
make_unsigned_or_unchanged
<
T
,
true
>
{
using
type
=
typename
std
::
make_unsigned
<
T
>::
type
;
};
#if FMT_SAFE_DURATION_CAST
// throwing version of safe_duration_cast
template
<
typename
To
,
typename
FromRep
,
typename
FromPeriod
>
To
fmt_safe_duration_cast
(
std
::
chrono
::
duration
<
FromRep
,
FromPeriod
>
from
)
{
int
ec
;
To
to
=
safe_duration_cast
::
safe_duration_cast
<
To
>
(
from
,
ec
);
if
(
ec
)
FMT_THROW
(
format_error
(
"cannot format duration"
));
return
to
;
}
#endif
template
<
typename
Rep
,
typename
Period
,
FMT_ENABLE_IF
(
std
::
is_integral
<
Rep
>
::
value
)
>
inline
std
::
chrono
::
duration
<
Rep
,
std
::
milli
>
get_milliseconds
(
std
::
chrono
::
duration
<
Rep
,
Period
>
d
)
{
// this may overflow and/or the result may not fit in the
// target type.
#if FMT_SAFE_DURATION_CAST
using
CommonSecondsType
=
typename
std
::
common_type
<
decltype
(
d
),
std
::
chrono
::
seconds
>::
type
;
const
auto
d_as_common
=
fmt_safe_duration_cast
<
CommonSecondsType
>
(
d
);
const
auto
d_as_whole_seconds
=
fmt_safe_duration_cast
<
std
::
chrono
::
seconds
>
(
d_as_common
);
// this conversion should be nonproblematic
const
auto
diff
=
d_as_common
-
d_as_whole_seconds
;
const
auto
ms
=
fmt_safe_duration_cast
<
std
::
chrono
::
duration
<
Rep
,
std
::
milli
>>
(
diff
);
return
ms
;
#else
auto
s
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
d
);
return
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
d
-
s
);
#endif
}
template
<
typename
Rep
,
typename
Period
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
Rep
>
::
value
)
>
inline
std
::
chrono
::
duration
<
Rep
,
std
::
milli
>
get_milliseconds
(
std
::
chrono
::
duration
<
Rep
,
Period
>
d
)
{
using
common_type
=
typename
std
::
common_type
<
Rep
,
std
::
intmax_t
>::
type
;
auto
ms
=
mod
(
d
.
count
()
*
static_cast
<
common_type
>
(
Period
::
num
)
/
static_cast
<
common_type
>
(
Period
::
den
)
*
1000
,
1000
);
return
std
::
chrono
::
duration
<
Rep
,
std
::
milli
>
(
static_cast
<
Rep
>
(
ms
));
}
template
<
typename
Rep
,
typename
OutputIt
>
OutputIt
format_chrono_duration_value
(
OutputIt
out
,
Rep
val
,
int
precision
)
{
if
(
precision
>=
0
)
return
format_to
(
out
,
"{:.{}f}"
,
val
,
precision
);
return
format_to
(
out
,
std
::
is_floating_point
<
Rep
>::
value
?
"{:g}"
:
"{}"
,
val
);
}
template
<
typename
Period
,
typename
OutputIt
>
static
OutputIt
format_chrono_duration_unit
(
OutputIt
out
)
{
if
(
const
char
*
unit
=
get_units
<
Period
>
())
return
format_to
(
out
,
"{}"
,
unit
);
if
(
Period
::
den
==
1
)
return
format_to
(
out
,
"[{}]s"
,
Period
::
num
);
return
format_to
(
out
,
"[{}/{}]s"
,
Period
::
num
,
Period
::
den
);
}
template
<
typename
FormatContext
,
typename
OutputIt
,
typename
Rep
,
typename
Period
>
struct
chrono_formatter
{
FormatContext
&
context
;
FormatContext
&
context
;
OutputIt
out
;
std
::
chrono
::
seconds
s
;
std
::
chrono
::
milliseconds
ms
;
int
precision
;
// rep is unsigned to avoid overflow.
using
rep
=
conditional_t
<
std
::
is_integral
<
Rep
>::
value
&&
sizeof
(
Rep
)
<
sizeof
(
int
),
unsigned
,
typename
make_unsigned_or_unchanged
<
Rep
>::
type
>
;
rep
val
;
using
seconds
=
std
::
chrono
::
duration
<
rep
>
;
seconds
s
;
using
milliseconds
=
std
::
chrono
::
duration
<
rep
,
std
::
milli
>
;
bool
negative
;
using
char_type
=
typename
FormatContext
::
char_type
;
explicit
chrono_formatter
(
FormatContext
&
ctx
,
OutputIt
o
,
std
::
chrono
::
duration
<
Rep
,
Period
>
d
)
:
context
(
ctx
),
out
(
o
),
val
(
d
.
count
()),
negative
(
false
)
{
if
(
d
.
count
()
<
0
)
{
val
=
0
-
val
;
negative
=
true
;
}
typedef
typename
FormatContext
::
char_type
char_type
;
// this may overflow and/or the result may not fit in the
// target type.
#if FMT_SAFE_DURATION_CAST
// might need checked conversion (rep!=Rep)
auto
tmpval
=
std
::
chrono
::
duration
<
rep
,
Period
>
(
val
);
s
=
fmt_safe_duration_cast
<
seconds
>
(
tmpval
);
#else
s
=
std
::
chrono
::
duration_cast
<
seconds
>
(
std
::
chrono
::
duration
<
rep
,
Period
>
(
val
));
#endif
}
explicit
chrono_formatter
(
FormatContext
&
ctx
,
OutputIt
o
)
:
context
(
ctx
),
out
(
o
)
{}
// returns true if nan or inf, writes to out.
bool
handle_nan_inf
()
{
if
(
isfinite
(
val
))
{
return
false
;
}
if
(
isnan
(
val
))
{
write_nan
();
return
true
;
}
// must be +-inf
if
(
val
>
0
)
{
write_pinf
();
}
else
{
write_ninf
();
}
return
true
;
}
int
hour
()
const
{
return
to_int
((
s
.
count
()
/
3600
)
%
24
);
}
Rep
hour
()
const
{
return
static_cast
<
Rep
>
(
mod
((
s
.
count
()
/
3600
),
24
)
);
}
int
hour12
()
const
{
auto
hour
=
to_int
((
s
.
count
()
/
3600
)
%
12
);
return
hour
>
0
?
hour
:
12
;
Rep
hour12
()
const
{
Rep
hour
=
static_cast
<
Rep
>
(
mod
((
s
.
count
()
/
3600
),
12
)
);
return
hour
<=
0
?
12
:
hour
;
}
int
minute
()
const
{
return
to_int
((
s
.
count
()
/
60
)
%
60
);
}
int
second
()
const
{
return
to_int
(
s
.
count
()
%
60
);
}
Rep
minute
()
const
{
return
static_cast
<
Rep
>
(
mod
((
s
.
count
()
/
60
),
60
)
);
}
Rep
second
()
const
{
return
static_cast
<
Rep
>
(
mod
(
s
.
count
(),
60
)
);
}
std
::
tm
time
()
const
{
auto
time
=
std
::
tm
();
time
.
tm_hour
=
hour
(
);
time
.
tm_min
=
minute
(
);
time
.
tm_sec
=
second
(
);
time
.
tm_hour
=
to_nonnegative_int
(
hour
(),
24
);
time
.
tm_min
=
to_nonnegative_int
(
minute
(),
60
);
time
.
tm_sec
=
to_nonnegative_int
(
second
(),
60
);
return
time
;
}
void
write
(
int
value
,
int
width
)
{
typedef
typename
int_traits
<
int
>::
main_type
main_type
;
main_type
n
=
to_unsigned
(
value
);
void
write_sign
()
{
if
(
negative
)
{
*
out
++
=
'-'
;
negative
=
false
;
}
}
void
write
(
Rep
value
,
int
width
)
{
write_sign
();
if
(
isnan
(
value
))
return
write_nan
();
uint32_or_64_t
<
int
>
n
=
to_unsigned
(
to_nonnegative_int
(
value
,
(
std
::
numeric_limits
<
int
>::
max
)()));
int
num_digits
=
internal
::
count_digits
(
n
);
if
(
width
>
num_digits
)
out
=
std
::
fill_n
(
out
,
width
-
num_digits
,
'0'
);
if
(
width
>
num_digits
)
out
=
std
::
fill_n
(
out
,
width
-
num_digits
,
'0'
);
out
=
format_decimal
<
char_type
>
(
out
,
n
,
num_digits
);
}
void
format_localized
(
const
tm
&
time
,
const
char
*
format
)
{
void
write_nan
()
{
std
::
copy_n
(
"nan"
,
3
,
out
);
}
void
write_pinf
()
{
std
::
copy_n
(
"inf"
,
3
,
out
);
}
void
write_ninf
()
{
std
::
copy_n
(
"-inf"
,
4
,
out
);
}
void
format_localized
(
const
tm
&
time
,
const
char
*
format
)
{
if
(
isnan
(
val
))
return
write_nan
();
auto
locale
=
context
.
locale
().
template
get
<
std
::
locale
>();
auto
&
facet
=
std
::
use_facet
<
std
::
time_put
<
char_type
>>
(
locale
);
auto
&
facet
=
std
::
use_facet
<
std
::
time_put
<
char_type
>>
(
locale
);
std
::
basic_ostringstream
<
char_type
>
os
;
os
.
imbue
(
locale
);
facet
.
put
(
os
,
os
,
' '
,
&
time
,
format
,
format
+
std
::
strlen
(
format
));
...
...
@@ -266,7 +604,7 @@ struct chrono_formatter {
std
::
copy
(
str
.
begin
(),
str
.
end
(),
out
);
}
void
on_text
(
const
char_type
*
begin
,
const
char_type
*
end
)
{
void
on_text
(
const
char_type
*
begin
,
const
char_type
*
end
)
{
std
::
copy
(
begin
,
end
,
out
);
}
...
...
@@ -286,46 +624,70 @@ struct chrono_formatter {
void
on_tz_name
()
{}
void
on_24_hour
(
numeric_system
ns
)
{
if
(
ns
==
numeric_system
::
standard
)
return
write
(
hour
(),
2
);
if
(
handle_nan_inf
())
return
;
if
(
ns
==
numeric_system
::
standard
)
return
write
(
hour
(),
2
);
auto
time
=
tm
();
time
.
tm_hour
=
hour
(
);
time
.
tm_hour
=
to_nonnegative_int
(
hour
(),
24
);
format_localized
(
time
,
"%OH"
);
}
void
on_12_hour
(
numeric_system
ns
)
{
if
(
ns
==
numeric_system
::
standard
)
return
write
(
hour12
(),
2
);
if
(
handle_nan_inf
())
return
;
if
(
ns
==
numeric_system
::
standard
)
return
write
(
hour12
(),
2
);
auto
time
=
tm
();
time
.
tm_hour
=
hour
(
);
time
.
tm_hour
=
to_nonnegative_int
(
hour12
(),
12
);
format_localized
(
time
,
"%OI"
);
}
void
on_minute
(
numeric_system
ns
)
{
if
(
ns
==
numeric_system
::
standard
)
return
write
(
minute
(),
2
);
if
(
handle_nan_inf
())
return
;
if
(
ns
==
numeric_system
::
standard
)
return
write
(
minute
(),
2
);
auto
time
=
tm
();
time
.
tm_min
=
minute
(
);
time
.
tm_min
=
to_nonnegative_int
(
minute
(),
60
);
format_localized
(
time
,
"%OM"
);
}
void
on_second
(
numeric_system
ns
)
{
if
(
handle_nan_inf
())
return
;
if
(
ns
==
numeric_system
::
standard
)
{
write
(
second
(),
2
);
#if FMT_SAFE_DURATION_CAST
// convert rep->Rep
using
duration_rep
=
std
::
chrono
::
duration
<
rep
,
Period
>
;
using
duration_Rep
=
std
::
chrono
::
duration
<
Rep
,
Period
>
;
auto
tmpval
=
fmt_safe_duration_cast
<
duration_Rep
>
(
duration_rep
{
val
});
#else
auto
tmpval
=
std
::
chrono
::
duration
<
Rep
,
Period
>
(
val
);
#endif
auto
ms
=
get_milliseconds
(
tmpval
);
if
(
ms
!=
std
::
chrono
::
milliseconds
(
0
))
{
*
out
++
=
'.'
;
write
(
to_int
(
ms
.
count
()
),
3
);
write
(
ms
.
count
(
),
3
);
}
return
;
}
auto
time
=
tm
();
time
.
tm_sec
=
second
(
);
time
.
tm_sec
=
to_nonnegative_int
(
second
(),
60
);
format_localized
(
time
,
"%OS"
);
}
void
on_12_hour_time
()
{
format_localized
(
time
(),
"%r"
);
}
void
on_12_hour_time
()
{
if
(
handle_nan_inf
())
return
;
format_localized
(
time
(),
"%r"
);
}
void
on_24_hour_time
()
{
if
(
handle_nan_inf
())
{
*
out
++
=
':'
;
handle_nan_inf
();
return
;
}
write
(
hour
(),
2
);
*
out
++
=
':'
;
write
(
minute
(),
2
);
...
...
@@ -334,115 +696,130 @@ struct chrono_formatter {
void
on_iso_time
()
{
on_24_hour_time
();
*
out
++
=
':'
;
if
(
handle_nan_inf
())
return
;
write
(
second
(),
2
);
}
void
on_am_pm
()
{
format_localized
(
time
(),
"%p"
);
}
void
on_am_pm
()
{
if
(
handle_nan_inf
())
return
;
format_localized
(
time
(),
"%p"
);
}
void
on_duration_value
()
{
if
(
handle_nan_inf
())
return
;
write_sign
();
out
=
format_chrono_duration_value
(
out
,
val
,
precision
);
}
void
on_duration_unit
()
{
out
=
format_chrono_duration_unit
<
Period
>
(
out
);
}
};
}
// namespace internal
template
<
typename
Period
>
FMT_CONSTEXPR
const
char
*
get_units
()
{
return
FMT_NULL
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
atto
>
()
{
return
"as"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
femto
>
()
{
return
"fs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
pico
>
()
{
return
"ps"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
nano
>
()
{
return
"ns"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
micro
>
()
{
return
"µs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
milli
>
()
{
return
"ms"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
centi
>
()
{
return
"cs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
deci
>
()
{
return
"ds"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
ratio
<
1
>>
()
{
return
"s"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
deca
>
()
{
return
"das"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
hecto
>
()
{
return
"hs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
kilo
>
()
{
return
"ks"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
mega
>
()
{
return
"Ms"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
giga
>
()
{
return
"Gs"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
tera
>
()
{
return
"Ts"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
peta
>
()
{
return
"Ps"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
exa
>
()
{
return
"Es"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
ratio
<
60
>>
()
{
return
"m"
;
}
template
<
>
FMT_CONSTEXPR
const
char
*
get_units
<
std
::
ratio
<
3600
>>
()
{
return
"h"
;
}
template
<
typename
Rep
,
typename
Period
,
typename
Char
>
struct
formatter
<
std
::
chrono
::
duration
<
Rep
,
Period
>
,
Char
>
{
private:
align_spec
spec
;
internal
::
arg_ref
<
Char
>
width_ref
;
basic_format_specs
<
Char
>
specs
;
int
precision
;
using
arg_ref_type
=
internal
::
arg_ref
<
Char
>
;
arg_ref_type
width_ref
;
arg_ref_type
precision_ref
;
mutable
basic_string_view
<
Char
>
format_str
;
typedef
std
::
chrono
::
duration
<
Rep
,
Period
>
duration
;
using
duration
=
std
::
chrono
::
duration
<
Rep
,
Period
>
;
struct
spec_handler
{
formatter
&
f
;
basic_parse_context
<
Char
>
&
context
;
formatter
&
f
;
basic_parse_context
<
Char
>&
context
;
basic_string_view
<
Char
>
format_str
;
typedef
internal
::
arg_ref
<
Char
>
arg_ref_type
;
template
<
typename
Id
>
FMT_CONSTEXPR
arg_ref_type
make_arg_ref
(
Id
arg_id
)
{
template
<
typename
Id
>
FMT_CONSTEXPR
arg_ref_type
make_arg_ref
(
Id
arg_id
)
{
context
.
check_arg_id
(
arg_id
);
return
arg_ref_type
(
arg_id
);
}
FMT_CONSTEXPR
arg_ref_type
make_arg_ref
(
basic_string_view
<
Char
>
arg_id
)
{
context
.
check_arg_id
(
arg_id
);
const
auto
str_val
=
internal
::
string_view_metadata
(
format_str
,
arg_id
);
return
arg_ref_type
(
str_val
);
}
FMT_CONSTEXPR
arg_ref_type
make_arg_ref
(
internal
::
auto_id
)
{
return
arg_ref_type
(
context
.
next_arg_id
());
}
void
on_error
(
const
char
*
msg
)
{
throw
format_error
(
msg
);
}
void
on_fill
(
Char
fill
)
{
f
.
spec
.
fill_
=
fill
;
}
void
on_align
(
alignment
align
)
{
f
.
spec
.
align_
=
align
;
}
void
on_width
(
unsigned
width
)
{
f
.
spec
.
width_
=
width
;
}
void
on_error
(
const
char
*
msg
)
{
FMT_THROW
(
format_error
(
msg
));
}
void
on_fill
(
Char
fill
)
{
f
.
specs
.
fill
[
0
]
=
fill
;
}
void
on_align
(
align_t
align
)
{
f
.
specs
.
align
=
align
;
}
void
on_width
(
unsigned
width
)
{
f
.
specs
.
width
=
width
;
}
void
on_precision
(
unsigned
precision
)
{
f
.
precision
=
precision
;
}
void
end_precision
()
{}
template
<
typename
Id
>
void
on_dynamic_width
(
Id
arg_id
)
{
template
<
typename
Id
>
void
on_dynamic_width
(
Id
arg_id
)
{
f
.
width_ref
=
make_arg_ref
(
arg_id
);
}
template
<
typename
Id
>
void
on_dynamic_precision
(
Id
arg_id
)
{
f
.
precision_ref
=
make_arg_ref
(
arg_id
);
}
};
public:
formatter
()
:
spec
()
{}
using
iterator
=
typename
basic_parse_context
<
Char
>::
iterator
;
struct
parse_range
{
iterator
begin
;
iterator
end
;
};
FMT_CONSTEXPR
auto
parse
(
basic_parse_context
<
Char
>
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
FMT_CONSTEXPR
parse_range
do_parse
(
basic_parse_context
<
Char
>&
ctx
)
{
auto
begin
=
ctx
.
begin
(),
end
=
ctx
.
end
();
if
(
begin
==
end
)
return
begin
;
spec_handler
handler
{
*
this
,
ctx
};
if
(
begin
==
end
||
*
begin
==
'}'
)
return
{
begin
,
begin
}
;
spec_handler
handler
{
*
this
,
ctx
,
format_str
};
begin
=
internal
::
parse_align
(
begin
,
end
,
handler
);
if
(
begin
==
end
)
return
begin
;
if
(
begin
==
end
)
return
{
begin
,
begin
}
;
begin
=
internal
::
parse_width
(
begin
,
end
,
handler
);
if
(
begin
==
end
)
return
{
begin
,
begin
};
if
(
*
begin
==
'.'
)
{
if
(
std
::
is_floating_point
<
Rep
>::
value
)
begin
=
internal
::
parse_precision
(
begin
,
end
,
handler
);
else
handler
.
on_error
(
"precision not allowed for this argument type"
);
}
end
=
parse_chrono_format
(
begin
,
end
,
internal
::
chrono_format_checker
());
format_str
=
basic_string_view
<
Char
>
(
&*
begin
,
internal
::
to_unsigned
(
end
-
begin
));
return
end
;
return
{
begin
,
end
};
}
public:
formatter
()
:
precision
(
-
1
)
{}
FMT_CONSTEXPR
auto
parse
(
basic_parse_context
<
Char
>&
ctx
)
->
decltype
(
ctx
.
begin
())
{
auto
range
=
do_parse
(
ctx
);
format_str
=
basic_string_view
<
Char
>
(
&*
range
.
begin
,
internal
::
to_unsigned
(
range
.
end
-
range
.
begin
));
return
range
.
end
;
}
template
<
typename
FormatContext
>
auto
format
(
const
duration
&
d
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
format
(
const
duration
&
d
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
begin
=
format_str
.
begin
(),
end
=
format_str
.
end
();
memory_buffer
buf
;
typedef
output_range
<
decltype
(
ctx
.
out
()),
Char
>
range
;
basic_writer
<
range
>
w
(
range
(
ctx
.
out
()));
if
(
begin
==
end
||
*
begin
==
'}'
)
{
if
(
const
char
*
unit
=
get_units
<
Period
>
())
format_to
(
buf
,
"{}{}"
,
d
.
count
(),
unit
);
else
if
(
Period
::
den
==
1
)
format_to
(
buf
,
"{}[{}]s"
,
d
.
count
(),
Period
::
num
);
else
format_to
(
buf
,
"{}[{}/{}]s"
,
d
.
count
(),
Period
::
num
,
Period
::
den
);
// As a possible future optimization, we could avoid extra copying if width
// 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
>
(
spec
.
width_
,
width_ref
,
ctx
);
specs
.
width
,
width_ref
,
ctx
,
format_str
.
begin
());
internal
::
handle_dynamic_spec
<
internal
::
precision_checker
>
(
precision
,
precision_ref
,
ctx
,
format_str
.
begin
());
if
(
begin
==
end
||
*
begin
==
'}'
)
{
out
=
internal
::
format_chrono_duration_value
(
out
,
d
.
count
(),
precision
);
internal
::
format_chrono_duration_unit
<
Period
>
(
out
);
}
else
{
auto
out
=
std
::
back_inserter
(
buf
);
internal
::
chrono_formatter
<
FormatContext
,
decltype
(
out
)
>
f
(
ctx
,
out
);
f
.
s
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
d
);
f
.
ms
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
d
-
f
.
s
);
internal
::
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
(),
spec
);
w
.
write
(
buf
.
data
(),
buf
.
size
(),
spec
s
);
return
w
.
out
();
}
};
...
...
include/spdlog/fmt/bundled/color.h
View file @
e149433a
...
...
@@ -12,41 +12,6 @@
FMT_BEGIN_NAMESPACE
#ifdef FMT_DEPRECATED_COLORS
// color and (v)print_colored are deprecated.
enum
color
{
black
,
red
,
green
,
yellow
,
blue
,
magenta
,
cyan
,
white
};
FMT_API
void
vprint_colored
(
color
c
,
string_view
format
,
format_args
args
);
FMT_API
void
vprint_colored
(
color
c
,
wstring_view
format
,
wformat_args
args
);
template
<
typename
...
Args
>
inline
void
print_colored
(
color
c
,
string_view
format_str
,
const
Args
&
...
args
)
{
vprint_colored
(
c
,
format_str
,
make_format_args
(
args
...));
}
template
<
typename
...
Args
>
inline
void
print_colored
(
color
c
,
wstring_view
format_str
,
const
Args
&
...
args
)
{
vprint_colored
(
c
,
format_str
,
make_format_args
<
wformat_context
>
(
args
...));
}
inline
void
vprint_colored
(
color
c
,
string_view
format
,
format_args
args
)
{
char
escape
[]
=
"
\x1b
[30m"
;
escape
[
3
]
=
static_cast
<
char
>
(
'0'
+
c
);
std
::
fputs
(
escape
,
stdout
);
vprint
(
format
,
args
);
std
::
fputs
(
internal
::
data
::
RESET_COLOR
,
stdout
);
}
inline
void
vprint_colored
(
color
c
,
wstring_view
format
,
wformat_args
args
)
{
wchar_t
escape
[]
=
L"
\x1b
[30m"
;
escape
[
3
]
=
static_cast
<
wchar_t
>
(
'0'
+
c
);
std
::
fputws
(
escape
,
stdout
);
vprint
(
format
,
args
);
std
::
fputws
(
internal
::
data
::
WRESET_COLOR
,
stdout
);
}
#else
enum
class
color
:
uint32_t
{
alice_blue
=
0xF0F8FF
,
// rgb(240,248,255)
antique_white
=
0xFAEBD7
,
// rgb(250,235,215)
...
...
@@ -208,26 +173,25 @@ enum class terminal_color : uint8_t {
bright_magenta
,
bright_cyan
,
bright_white
};
// enum class terminal_color
};
enum
class
emphasis
:
uint8_t
{
bold
=
1
,
italic
=
1
<<
1
,
underline
=
1
<<
2
,
strikethrough
=
1
<<
3
};
// enum class emphasis
};
// rgb is a struct for red, green and blue colors.
// We use rgb as name because some editors will show it as color direct in the
// editor.
// Using the name "rgb" makes some editors show the color in a tooltip.
struct
rgb
{
FMT_CONSTEXPR
_DECL
rgb
()
:
r
(
0
),
g
(
0
),
b
(
0
)
{}
FMT_CONSTEXPR
_DECL
rgb
(
uint8_t
r_
,
uint8_t
g_
,
uint8_t
b_
)
:
r
(
r_
),
g
(
g_
),
b
(
b_
)
{}
FMT_CONSTEXPR_DECL
rgb
(
uint32_t
hex
)
:
r
((
hex
>>
16
)
&
0xFF
),
g
((
hex
>>
8
)
&
0xFF
),
b
((
hex
)
&
0xFF
)
{}
FMT_CONSTEXPR_DECL
rgb
(
color
hex
)
:
r
((
uint32_t
(
hex
)
>>
16
)
&
0xFF
),
g
((
uint32_t
(
hex
)
>>
8
)
&
0xFF
),
FMT_CONSTEXPR
rgb
()
:
r
(
0
),
g
(
0
),
b
(
0
)
{}
FMT_CONSTEXPR
rgb
(
uint8_t
r_
,
uint8_t
g_
,
uint8_t
b_
)
:
r
(
r_
),
g
(
g_
),
b
(
b_
)
{}
FMT_CONSTEXPR
rgb
(
uint32_t
hex
)
:
r
((
hex
>>
16
)
&
0xFF
),
g
((
hex
>>
8
)
&
0xFF
),
b
(
hex
&
0xFF
)
{}
FMT_CONSTEXPR
rgb
(
color
hex
)
:
r
((
uint32_t
(
hex
)
>>
16
)
&
0xFF
),
g
((
uint32_t
(
hex
)
>>
8
)
&
0xFF
),
b
(
uint32_t
(
hex
)
&
0xFF
)
{}
uint8_t
r
;
uint8_t
g
;
...
...
@@ -238,19 +202,17 @@ namespace internal {
// color is a struct of either a rgb color or a terminal color.
struct
color_type
{
FMT_CONSTEXPR
color_type
()
FMT_NOEXCEPT
:
is_rgb
(),
value
{}
{}
FMT_CONSTEXPR
color_type
(
color
rgb_color
)
FMT_NOEXCEPT
:
is_rgb
(
true
),
value
{}
{
FMT_CONSTEXPR
color_type
()
FMT_NOEXCEPT
:
is_rgb
(),
value
{}
{}
FMT_CONSTEXPR
color_type
(
color
rgb_color
)
FMT_NOEXCEPT
:
is_rgb
(
true
),
value
{}
{
value
.
rgb_color
=
static_cast
<
uint32_t
>
(
rgb_color
);
}
FMT_CONSTEXPR
color_type
(
rgb
rgb_color
)
FMT_NOEXCEPT
:
is_rgb
(
true
),
value
{}
{
value
.
rgb_color
=
(
static_cast
<
uint32_t
>
(
rgb_color
.
r
)
<<
16
)
|
(
static_cast
<
uint32_t
>
(
rgb_color
.
g
)
<<
8
)
|
rgb_color
.
b
;
FMT_CONSTEXPR
color_type
(
rgb
rgb_color
)
FMT_NOEXCEPT
:
is_rgb
(
true
),
value
{}
{
value
.
rgb_color
=
(
static_cast
<
uint32_t
>
(
rgb_color
.
r
)
<<
16
)
|
(
static_cast
<
uint32_t
>
(
rgb_color
.
g
)
<<
8
)
|
rgb_color
.
b
;
}
FMT_CONSTEXPR
color_type
(
terminal_color
term_color
)
FMT_NOEXCEPT
:
is_rgb
(),
value
{}
{
FMT_CONSTEXPR
color_type
(
terminal_color
term_color
)
FMT_NOEXCEPT
:
is_rgb
(),
value
{}
{
value
.
term_color
=
static_cast
<
uint8_t
>
(
term_color
);
}
bool
is_rgb
;
...
...
@@ -265,15 +227,17 @@ struct color_type {
class
text_style
{
public:
FMT_CONSTEXPR
text_style
(
emphasis
em
=
emphasis
())
FMT_NOEXCEPT
:
set_foreground_color
(),
set_background_color
(),
ems
(
em
)
{}
:
set_foreground_color
(),
set_background_color
(),
ems
(
em
)
{}
FMT_CONSTEXPR
text_style
&
operator
|=
(
const
text_style
&
rhs
)
{
FMT_CONSTEXPR
text_style
&
operator
|=
(
const
text_style
&
rhs
)
{
if
(
!
set_foreground_color
)
{
set_foreground_color
=
rhs
.
set_foreground_color
;
foreground_color
=
rhs
.
foreground_color
;
}
else
if
(
rhs
.
set_foreground_color
)
{
if
(
!
foreground_color
.
is_rgb
||
!
rhs
.
foreground_color
.
is_rgb
)
throw
format_error
(
"can't OR a terminal color"
);
FMT_THROW
(
format_error
(
"can't OR a terminal color"
)
);
foreground_color
.
value
.
rgb_color
|=
rhs
.
foreground_color
.
value
.
rgb_color
;
}
...
...
@@ -282,7 +246,7 @@ class text_style {
background_color
=
rhs
.
background_color
;
}
else
if
(
rhs
.
set_background_color
)
{
if
(
!
background_color
.
is_rgb
||
!
rhs
.
background_color
.
is_rgb
)
throw
format_error
(
"can't OR a terminal color"
);
FMT_THROW
(
format_error
(
"can't OR a terminal color"
)
);
background_color
.
value
.
rgb_color
|=
rhs
.
background_color
.
value
.
rgb_color
;
}
...
...
@@ -291,18 +255,18 @@ class text_style {
return
*
this
;
}
friend
FMT_CONSTEXPR
text_style
operator
|
(
text_style
lhs
,
const
text_style
&
rhs
)
{
friend
FMT_CONSTEXPR
text_style
operator
|
(
text_style
lhs
,
const
text_style
&
rhs
)
{
return
lhs
|=
rhs
;
}
FMT_CONSTEXPR
text_style
&
operator
&=
(
const
text_style
&
rhs
)
{
FMT_CONSTEXPR
text_style
&
operator
&=
(
const
text_style
&
rhs
)
{
if
(
!
set_foreground_color
)
{
set_foreground_color
=
rhs
.
set_foreground_color
;
foreground_color
=
rhs
.
foreground_color
;
}
else
if
(
rhs
.
set_foreground_color
)
{
if
(
!
foreground_color
.
is_rgb
||
!
rhs
.
foreground_color
.
is_rgb
)
throw
format_error
(
"can't AND a terminal color"
);
FMT_THROW
(
format_error
(
"can't AND a terminal color"
)
);
foreground_color
.
value
.
rgb_color
&=
rhs
.
foreground_color
.
value
.
rgb_color
;
}
...
...
@@ -311,7 +275,7 @@ class text_style {
background_color
=
rhs
.
background_color
;
}
else
if
(
rhs
.
set_background_color
)
{
if
(
!
background_color
.
is_rgb
||
!
rhs
.
background_color
.
is_rgb
)
throw
format_error
(
"can't AND a terminal color"
);
FMT_THROW
(
format_error
(
"can't AND a terminal color"
)
);
background_color
.
value
.
rgb_color
&=
rhs
.
background_color
.
value
.
rgb_color
;
}
...
...
@@ -320,8 +284,8 @@ class text_style {
return
*
this
;
}
friend
FMT_CONSTEXPR
text_style
operator
&
(
text_style
lhs
,
const
text_style
&
rhs
)
{
friend
FMT_CONSTEXPR
text_style
operator
&
(
text_style
lhs
,
const
text_style
&
rhs
)
{
return
lhs
&=
rhs
;
}
...
...
@@ -347,7 +311,7 @@ class text_style {
return
ems
;
}
private:
private:
FMT_CONSTEXPR
text_style
(
bool
is_foreground
,
internal
::
color_type
text_color
)
FMT_NOEXCEPT
:
set_foreground_color
(),
...
...
@@ -388,19 +352,17 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
namespace
internal
{
template
<
typename
Char
>
struct
ansi_color_escape
{
template
<
typename
Char
>
struct
ansi_color_escape
{
FMT_CONSTEXPR
ansi_color_escape
(
internal
::
color_type
text_color
,
const
char
*
esc
)
FMT_NOEXCEPT
{
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
==
internal
::
data
::
BACKGROUND_COLOR
;
bool
is_background
=
esc
==
internal
::
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
;
if
(
is_background
)
value
+=
10u
;
std
::
size_t
index
=
0
;
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'\x1b'
);
...
...
@@ -430,19 +392,15 @@ struct ansi_color_escape {
FMT_CONSTEXPR
ansi_color_escape
(
emphasis
em
)
FMT_NOEXCEPT
{
uint8_t
em_codes
[
4
]
=
{};
uint8_t
em_bits
=
static_cast
<
uint8_t
>
(
em
);
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
bold
))
em_codes
[
0
]
=
1
;
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
italic
))
em_codes
[
1
]
=
3
;
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
underline
))
em_codes
[
2
]
=
4
;
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
bold
))
em_codes
[
0
]
=
1
;
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
italic
))
em_codes
[
1
]
=
3
;
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
underline
))
em_codes
[
2
]
=
4
;
if
(
em_bits
&
static_cast
<
uint8_t
>
(
emphasis
::
strikethrough
))
em_codes
[
3
]
=
9
;
std
::
size_t
index
=
0
;
for
(
int
i
=
0
;
i
<
4
;
++
i
)
{
if
(
!
em_codes
[
i
])
continue
;
if
(
!
em_codes
[
i
])
continue
;
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'\x1b'
);
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'['
);
buffer
[
index
++
]
=
static_cast
<
Char
>
(
'0'
+
em_codes
[
i
]);
...
...
@@ -450,12 +408,17 @@ struct ansi_color_escape {
}
buffer
[
index
++
]
=
static_cast
<
Char
>
(
0
);
}
FMT_CONSTEXPR
operator
const
Char
*
()
const
FMT_NOEXCEPT
{
return
buffer
;
}
FMT_CONSTEXPR
operator
const
Char
*
()
const
FMT_NOEXCEPT
{
return
buffer
;
}
FMT_CONSTEXPR
const
Char
*
begin
()
const
FMT_NOEXCEPT
{
return
buffer
;
}
FMT_CONSTEXPR
const
Char
*
end
()
const
FMT_NOEXCEPT
{
return
buffer
+
std
::
strlen
(
buffer
);
}
private:
private:
Char
buffer
[
7u
+
3u
*
4u
+
1u
];
static
FMT_CONSTEXPR
void
to_esc
(
uint8_t
c
,
Char
*
out
,
static
FMT_CONSTEXPR
void
to_esc
(
uint8_t
c
,
Char
*
out
,
char
delimiter
)
FMT_NOEXCEPT
{
out
[
0
]
=
static_cast
<
Char
>
(
'0'
+
c
/
100
);
out
[
1
]
=
static_cast
<
Char
>
(
'0'
+
c
/
10
%
10
);
...
...
@@ -465,62 +428,85 @@ private:
};
template
<
typename
Char
>
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_foreground_color
(
internal
::
color_type
foreground
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
foreground
,
internal
::
data
::
FOREGROUND_COLOR
);
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_foreground_color
(
internal
::
color_type
foreground
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
foreground
,
internal
::
data
::
foreground_color
);
}
template
<
typename
Char
>
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_background_color
(
internal
::
color_type
background
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
background
,
internal
::
data
::
BACKGROUND_COLOR
);
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_background_color
(
internal
::
color_type
background
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
background
,
internal
::
data
::
background_color
);
}
template
<
typename
Char
>
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_emphasis
(
emphasis
em
)
FMT_NOEXCEPT
{
FMT_CONSTEXPR
ansi_color_escape
<
Char
>
make_emphasis
(
emphasis
em
)
FMT_NOEXCEPT
{
return
ansi_color_escape
<
Char
>
(
em
);
}
template
<
typename
Char
>
inline
void
fputs
(
const
Char
*
chars
,
FILE
*
stream
)
FMT_NOEXCEPT
{
inline
void
fputs
(
const
Char
*
chars
,
FILE
*
stream
)
FMT_NOEXCEPT
{
std
::
fputs
(
chars
,
stream
);
}
template
<
>
inline
void
fputs
<
wchar_t
>
(
const
wchar_t
*
chars
,
FILE
*
stream
)
FMT_NOEXCEPT
{
inline
void
fputs
<
wchar_t
>
(
const
wchar_t
*
chars
,
FILE
*
stream
)
FMT_NOEXCEPT
{
std
::
fputws
(
chars
,
stream
);
}
template
<
typename
Char
>
inline
void
reset_color
(
FILE
*
stream
)
FMT_NOEXCEPT
{
fputs
(
internal
::
data
::
RESET_COLOR
,
stream
);
template
<
typename
Char
>
inline
void
reset_color
(
FILE
*
stream
)
FMT_NOEXCEPT
{
fputs
(
internal
::
data
::
reset_color
,
stream
);
}
template
<
>
inline
void
reset_color
<
wchar_t
>
(
FILE
*
stream
)
FMT_NOEXCEPT
{
fputs
(
internal
::
data
::
WRESET_COLOR
,
stream
);
template
<
>
inline
void
reset_color
<
wchar_t
>
(
FILE
*
stream
)
FMT_NOEXCEPT
{
fputs
(
internal
::
data
::
wreset_color
,
stream
);
}
// The following specialiazation disables using std::FILE as a character type,
// which is needed because or else
// fmt::print(stderr, fmt::emphasis::bold, "");
// would take stderr (a std::FILE *) as the format string.
template
<
>
struct
is_string
<
std
::
FILE
*>
:
std
::
false_type
{};
template
<
>
struct
is_string
<
const
std
::
FILE
*>
:
std
::
false_type
{};
template
<
typename
Char
>
inline
void
reset_color
(
basic_memory_buffer
<
Char
>&
buffer
)
FMT_NOEXCEPT
{
const
char
*
begin
=
data
::
reset_color
;
const
char
*
end
=
begin
+
sizeof
(
data
::
reset_color
)
-
1
;
buffer
.
append
(
begin
,
end
);
}
template
<
typename
Char
>
std
::
basic_string
<
Char
>
vformat
(
const
text_style
&
ts
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
Char
>
>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
bool
has_style
=
false
;
if
(
ts
.
has_emphasis
())
{
has_style
=
true
;
ansi_color_escape
<
Char
>
escape
=
make_emphasis
<
Char
>
(
ts
.
get_emphasis
());
buffer
.
append
(
escape
.
begin
(),
escape
.
end
());
}
if
(
ts
.
has_foreground
())
{
has_style
=
true
;
ansi_color_escape
<
Char
>
escape
=
make_foreground_color
<
Char
>
(
ts
.
get_foreground
());
buffer
.
append
(
escape
.
begin
(),
escape
.
end
());
}
if
(
ts
.
has_background
())
{
has_style
=
true
;
ansi_color_escape
<
Char
>
escape
=
make_background_color
<
Char
>
(
ts
.
get_background
());
buffer
.
append
(
escape
.
begin
(),
escape
.
end
());
}
internal
::
vformat_to
(
buffer
,
format_str
,
args
);
if
(
has_style
)
{
reset_color
<
Char
>
(
buffer
);
}
return
fmt
::
to_string
(
buffer
);
}
}
// namespace internal
template
<
typename
S
,
typename
Char
=
typename
internal
::
char_t
<
S
>
::
type
>
void
vprint
(
std
::
FILE
*
f
,
const
text_style
&
ts
,
const
S
&
format
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
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
)
{
bool
has_style
=
false
;
if
(
ts
.
has_emphasis
())
{
has_style
=
true
;
internal
::
fputs
<
Char
>
(
internal
::
make_emphasis
<
Char
>
(
ts
.
get_emphasis
()),
f
);
internal
::
fputs
<
Char
>
(
internal
::
make_emphasis
<
Char
>
(
ts
.
get_emphasis
()),
f
);
}
if
(
ts
.
has_foreground
())
{
has_style
=
true
;
...
...
@@ -545,15 +531,14 @@ void vprint(std::FILE *f, const text_style &ts, const S &format,
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template
<
typename
S
tring
,
typename
...
Args
>
typename
std
::
enable_if
<
internal
::
is_string
<
String
>::
value
>::
type
print
(
std
::
FILE
*
f
,
const
text_style
&
ts
,
const
String
&
format_str
,
const
Args
&
...
args
)
{
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_string
<
S
>
::
value
)
>
void
print
(
std
::
FILE
*
f
,
const
text_style
&
ts
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
internal
::
check_format_string
<
Args
...
>
(
format_str
);
typedef
typename
internal
::
char_t
<
String
>::
type
char_t
;
typedef
typename
buffer_context
<
char_t
>::
type
context_t
;
format_arg_store
<
context_t
,
Args
...
>
as
{
args
...};
vprint
(
f
,
ts
,
format_str
,
basic_format_args
<
context_t
>
(
as
));
using
context
=
buffer_context
<
char_t
<
S
>
>
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...};
vprint
(
f
,
ts
,
format_str
,
basic_format_args
<
context
>
(
as
));
}
/**
...
...
@@ -563,14 +548,37 @@ typename std::enable_if<internal::is_string<String>::value>::type print(
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template
<
typename
String
,
typename
...
Args
>
typename
std
::
enable_if
<
internal
::
is_string
<
String
>::
value
>::
type
print
(
const
text_style
&
ts
,
const
String
&
format_str
,
const
Args
&
...
args
)
{
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_string
<
S
>
::
value
)
>
void
print
(
const
text_style
&
ts
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
return
print
(
stdout
,
ts
,
format_str
,
args
...);
}
#endif
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
vformat
(
const
text_style
&
ts
,
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
Char
>
>
args
)
{
return
internal
::
vformat
(
ts
,
to_string_view
(
format_str
),
args
);
}
/**
\rst
Formats arguments and returns the result as a string using ANSI
escape sequences to specify text formatting.
**Example**::
#include <fmt/color.h>
std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
"The answer is {}", 42);
\endrst
*/
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
internal
::
vformat
(
ts
,
to_string_view
(
format_str
),
{
internal
::
make_args_checked
(
format_str
,
args
...)});
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/compile.h
0 → 100644
View file @
e149433a
// Formatting library for C++ - experimental format string compilation
//
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COMPILE_H_
#define FMT_COMPILE_H_
#include <vector>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace
internal
{
template
<
typename
Char
>
struct
format_part
{
public:
struct
named_argument_id
{
FMT_CONSTEXPR
named_argument_id
(
internal
::
string_view_metadata
id
)
:
id
(
id
)
{}
internal
::
string_view_metadata
id
;
};
struct
argument_id
{
FMT_CONSTEXPR
argument_id
()
:
argument_id
(
0u
)
{}
FMT_CONSTEXPR
argument_id
(
unsigned
id
)
:
which
(
which_arg_id
::
index
),
val
(
id
)
{}
FMT_CONSTEXPR
argument_id
(
internal
::
string_view_metadata
id
)
:
which
(
which_arg_id
::
named_index
),
val
(
id
)
{}
enum
class
which_arg_id
{
index
,
named_index
};
which_arg_id
which
;
union
value
{
FMT_CONSTEXPR
value
()
:
index
(
0u
)
{}
FMT_CONSTEXPR
value
(
unsigned
id
)
:
index
(
id
)
{}
FMT_CONSTEXPR
value
(
internal
::
string_view_metadata
id
)
:
named_index
(
id
)
{}
unsigned
index
;
internal
::
string_view_metadata
named_index
;
}
val
;
};
struct
specification
{
FMT_CONSTEXPR
specification
()
:
arg_id
(
0u
)
{}
FMT_CONSTEXPR
specification
(
unsigned
id
)
:
arg_id
(
id
)
{}
FMT_CONSTEXPR
specification
(
internal
::
string_view_metadata
id
)
:
arg_id
(
id
)
{}
argument_id
arg_id
;
internal
::
dynamic_format_specs
<
Char
>
parsed_specs
;
};
FMT_CONSTEXPR
format_part
()
:
which
(
kind
::
argument_id
),
end_of_argument_id
(
0u
),
val
(
0u
)
{}
FMT_CONSTEXPR
format_part
(
internal
::
string_view_metadata
text
)
:
which
(
kind
::
text
),
end_of_argument_id
(
0u
),
val
(
text
)
{}
FMT_CONSTEXPR
format_part
(
unsigned
id
)
:
which
(
kind
::
argument_id
),
end_of_argument_id
(
0u
),
val
(
id
)
{}
FMT_CONSTEXPR
format_part
(
named_argument_id
arg_id
)
:
which
(
kind
::
named_argument_id
),
end_of_argument_id
(
0u
),
val
(
arg_id
)
{}
FMT_CONSTEXPR
format_part
(
specification
spec
)
:
which
(
kind
::
specification
),
end_of_argument_id
(
0u
),
val
(
spec
)
{}
enum
class
kind
{
argument_id
,
named_argument_id
,
text
,
specification
};
kind
which
;
std
::
size_t
end_of_argument_id
;
union
value
{
FMT_CONSTEXPR
value
()
:
arg_id
(
0u
)
{}
FMT_CONSTEXPR
value
(
unsigned
id
)
:
arg_id
(
id
)
{}
FMT_CONSTEXPR
value
(
named_argument_id
named_id
)
:
named_arg_id
(
named_id
.
id
)
{}
FMT_CONSTEXPR
value
(
internal
::
string_view_metadata
t
)
:
text
(
t
)
{}
FMT_CONSTEXPR
value
(
specification
s
)
:
spec
(
s
)
{}
unsigned
arg_id
;
internal
::
string_view_metadata
named_arg_id
;
internal
::
string_view_metadata
text
;
specification
spec
;
}
val
;
};
template
<
typename
Char
,
typename
PartsContainer
>
class
format_preparation_handler
:
public
internal
::
error_handler
{
private:
using
part
=
format_part
<
Char
>
;
public:
using
iterator
=
typename
basic_string_view
<
Char
>::
iterator
;
FMT_CONSTEXPR
format_preparation_handler
(
basic_string_view
<
Char
>
format
,
PartsContainer
&
parts
)
:
parts_
(
parts
),
format_
(
format
),
parse_context_
(
format
)
{}
FMT_CONSTEXPR
void
on_text
(
const
Char
*
begin
,
const
Char
*
end
)
{
if
(
begin
==
end
)
return
;
const
auto
offset
=
begin
-
format_
.
data
();
const
auto
size
=
end
-
begin
;
parts_
.
push_back
(
part
(
string_view_metadata
(
offset
,
size
)));
}
FMT_CONSTEXPR
void
on_arg_id
()
{
parts_
.
push_back
(
part
(
parse_context_
.
next_arg_id
()));
}
FMT_CONSTEXPR
void
on_arg_id
(
unsigned
id
)
{
parse_context_
.
check_arg_id
(
id
);
parts_
.
push_back
(
part
(
id
));
}
FMT_CONSTEXPR
void
on_arg_id
(
basic_string_view
<
Char
>
id
)
{
const
auto
view
=
string_view_metadata
(
format_
,
id
);
const
auto
arg_id
=
typename
part
::
named_argument_id
(
view
);
parts_
.
push_back
(
part
(
arg_id
));
}
FMT_CONSTEXPR
void
on_replacement_field
(
const
Char
*
ptr
)
{
parts_
.
back
().
end_of_argument_id
=
ptr
-
format_
.
begin
();
}
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
const
Char
*
begin
,
const
Char
*
end
)
{
const
auto
specs_offset
=
to_unsigned
(
begin
-
format_
.
begin
());
using
parse_context
=
basic_parse_context
<
Char
>
;
internal
::
dynamic_format_specs
<
Char
>
parsed_specs
;
dynamic_specs_handler
<
parse_context
>
handler
(
parsed_specs
,
parse_context_
);
begin
=
parse_format_specs
(
begin
,
end
,
handler
);
if
(
*
begin
!=
'}'
)
on_error
(
"missing '}' in format string"
);
auto
&
last_part
=
parts_
.
back
();
auto
specs
=
last_part
.
which
==
part
::
kind
::
argument_id
?
typename
part
::
specification
(
last_part
.
val
.
arg_id
)
:
typename
part
::
specification
(
last_part
.
val
.
named_arg_id
);
specs
.
parsed_specs
=
parsed_specs
;
last_part
=
part
(
specs
);
last_part
.
end_of_argument_id
=
specs_offset
;
return
begin
;
}
private:
PartsContainer
&
parts_
;
basic_string_view
<
Char
>
format_
;
basic_parse_context
<
Char
>
parse_context_
;
};
template
<
typename
Format
,
typename
PreparedPartsProvider
,
typename
...
Args
>
class
prepared_format
{
public:
using
char_type
=
char_t
<
Format
>
;
using
format_part_t
=
format_part
<
char_type
>
;
constexpr
prepared_format
(
Format
f
)
:
format_
(
std
::
move
(
f
)),
parts_provider_
(
to_string_view
(
format_
))
{}
prepared_format
()
=
delete
;
using
context
=
buffer_context
<
char_type
>
;
template
<
typename
Range
,
typename
Context
>
auto
vformat_to
(
Range
out
,
basic_format_args
<
Context
>
args
)
const
->
typename
Context
::
iterator
{
const
auto
format_view
=
internal
::
to_string_view
(
format_
);
basic_parse_context
<
char_type
>
parse_ctx
(
format_view
);
Context
ctx
(
out
.
begin
(),
args
);
const
auto
&
parts
=
parts_provider_
.
parts
();
for
(
auto
part_it
=
parts
.
begin
();
part_it
!=
parts
.
end
();
++
part_it
)
{
const
auto
&
part
=
*
part_it
;
const
auto
&
value
=
part
.
val
;
switch
(
part
.
which
)
{
case
format_part_t
:
:
kind
::
text
:
{
const
auto
text
=
value
.
text
.
to_view
(
format_view
.
data
());
auto
output
=
ctx
.
out
();
auto
&&
it
=
internal
::
reserve
(
output
,
text
.
size
());
it
=
std
::
copy_n
(
text
.
begin
(),
text
.
size
(),
it
);
ctx
.
advance_to
(
output
);
}
break
;
case
format_part_t
:
:
kind
::
argument_id
:
{
advance_parse_context_to_specification
(
parse_ctx
,
part
);
format_arg
<
Range
>
(
parse_ctx
,
ctx
,
value
.
arg_id
);
}
break
;
case
format_part_t
:
:
kind
::
named_argument_id
:
{
advance_parse_context_to_specification
(
parse_ctx
,
part
);
const
auto
named_arg_id
=
value
.
named_arg_id
.
to_view
(
format_view
.
data
());
format_arg
<
Range
>
(
parse_ctx
,
ctx
,
named_arg_id
);
}
break
;
case
format_part_t
:
:
kind
::
specification
:
{
const
auto
&
arg_id_value
=
value
.
spec
.
arg_id
.
val
;
const
auto
arg
=
value
.
spec
.
arg_id
.
which
==
format_part_t
::
argument_id
::
which_arg_id
::
index
?
ctx
.
arg
(
arg_id_value
.
index
)
:
ctx
.
arg
(
arg_id_value
.
named_index
.
to_view
(
to_string_view
(
format_
).
data
()));
auto
specs
=
value
.
spec
.
parsed_specs
;
handle_dynamic_spec
<
internal
::
width_checker
>
(
specs
.
width
,
specs
.
width_ref
,
ctx
,
format_view
.
begin
());
handle_dynamic_spec
<
internal
::
precision_checker
>
(
specs
.
precision
,
specs
.
precision_ref
,
ctx
,
format_view
.
begin
());
check_prepared_specs
(
specs
,
arg
.
type
());
advance_parse_context_to_specification
(
parse_ctx
,
part
);
ctx
.
advance_to
(
visit_format_arg
(
arg_formatter
<
Range
>
(
ctx
,
nullptr
,
&
specs
),
arg
));
}
break
;
}
}
return
ctx
.
out
();
}
private:
void
advance_parse_context_to_specification
(
basic_parse_context
<
char_type
>&
parse_ctx
,
const
format_part_t
&
part
)
const
{
const
auto
view
=
to_string_view
(
format_
);
const
auto
specification_begin
=
view
.
data
()
+
part
.
end_of_argument_id
;
advance_to
(
parse_ctx
,
specification_begin
);
}
template
<
typename
Range
,
typename
Context
,
typename
Id
>
void
format_arg
(
basic_parse_context
<
char_type
>&
parse_ctx
,
Context
&
ctx
,
Id
arg_id
)
const
{
parse_ctx
.
check_arg_id
(
arg_id
);
const
auto
stopped_at
=
visit_format_arg
(
arg_formatter
<
Range
>
(
ctx
),
ctx
.
arg
(
arg_id
));
ctx
.
advance_to
(
stopped_at
);
}
template
<
typename
Char
>
void
check_prepared_specs
(
const
basic_format_specs
<
Char
>&
specs
,
internal
::
type
arg_type
)
const
{
internal
::
error_handler
h
;
numeric_specs_checker
<
internal
::
error_handler
>
checker
(
h
,
arg_type
);
if
(
specs
.
align
==
align
::
numeric
)
checker
.
require_numeric_argument
();
if
(
specs
.
sign
!=
sign
::
none
)
checker
.
check_sign
();
if
(
specs
.
alt
)
checker
.
require_numeric_argument
();
if
(
specs
.
precision
>=
0
)
checker
.
check_precision
();
}
private:
Format
format_
;
PreparedPartsProvider
parts_provider_
;
};
template
<
typename
Char
>
struct
part_counter
{
unsigned
num_parts
=
0
;
FMT_CONSTEXPR
void
on_text
(
const
Char
*
begin
,
const
Char
*
end
)
{
if
(
begin
!=
end
)
++
num_parts
;
}
FMT_CONSTEXPR
void
on_arg_id
()
{
++
num_parts
;
}
FMT_CONSTEXPR
void
on_arg_id
(
unsigned
)
{
++
num_parts
;
}
FMT_CONSTEXPR
void
on_arg_id
(
basic_string_view
<
Char
>
)
{
++
num_parts
;
}
FMT_CONSTEXPR
void
on_replacement_field
(
const
Char
*
)
{}
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
const
Char
*
begin
,
const
Char
*
end
)
{
// Find the matching brace.
unsigned
braces_counter
=
0
;
for
(;
begin
!=
end
;
++
begin
)
{
if
(
*
begin
==
'{'
)
{
++
braces_counter
;
}
else
if
(
*
begin
==
'}'
)
{
if
(
braces_counter
==
0u
)
break
;
--
braces_counter
;
}
}
return
begin
;
}
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{}
};
template
<
typename
Format
>
class
compiletime_prepared_parts_type_provider
{
private:
using
char_type
=
char_t
<
Format
>
;
static
FMT_CONSTEXPR
unsigned
count_parts
()
{
FMT_CONSTEXPR_DECL
const
auto
text
=
to_string_view
(
Format
{});
part_counter
<
char_type
>
counter
;
internal
::
parse_format_string
<
/*IS_CONSTEXPR=*/
true
>
(
text
,
counter
);
return
counter
.
num_parts
;
}
// Workaround for old compilers. Compiletime parts preparation will not be
// performed with them anyway.
#if FMT_USE_CONSTEXPR
static
FMT_CONSTEXPR_DECL
const
unsigned
number_of_format_parts
=
compiletime_prepared_parts_type_provider
::
count_parts
();
#else
static
const
unsigned
number_of_format_parts
=
0u
;
#endif
public:
template
<
unsigned
N
>
struct
format_parts_array
{
using
value_type
=
format_part
<
char_type
>
;
FMT_CONSTEXPR
format_parts_array
()
:
arr
{}
{}
FMT_CONSTEXPR
value_type
&
operator
[](
unsigned
ind
)
{
return
arr
[
ind
];
}
FMT_CONSTEXPR
const
value_type
*
begin
()
const
{
return
arr
;
}
FMT_CONSTEXPR
const
value_type
*
end
()
const
{
return
begin
()
+
N
;
}
private:
value_type
arr
[
N
];
};
struct
empty
{
// Parts preparator will search for it
using
value_type
=
format_part
<
char_type
>
;
};
using
type
=
conditional_t
<
number_of_format_parts
!=
0
,
format_parts_array
<
number_of_format_parts
>
,
empty
>
;
};
template
<
typename
Parts
>
class
compiletime_prepared_parts_collector
{
private:
using
format_part
=
typename
Parts
::
value_type
;
public:
FMT_CONSTEXPR
explicit
compiletime_prepared_parts_collector
(
Parts
&
parts
)
:
parts_
{
parts
},
counter_
{
0u
}
{}
FMT_CONSTEXPR
void
push_back
(
format_part
part
)
{
parts_
[
counter_
++
]
=
part
;
}
FMT_CONSTEXPR
format_part
&
back
()
{
return
parts_
[
counter_
-
1
];
}
private:
Parts
&
parts_
;
unsigned
counter_
;
};
template
<
typename
PartsContainer
,
typename
Char
>
FMT_CONSTEXPR
PartsContainer
prepare_parts
(
basic_string_view
<
Char
>
format
)
{
PartsContainer
parts
;
internal
::
parse_format_string
<
/*IS_CONSTEXPR=*/
false
>
(
format
,
format_preparation_handler
<
Char
,
PartsContainer
>
(
format
,
parts
));
return
parts
;
}
template
<
typename
PartsContainer
,
typename
Char
>
FMT_CONSTEXPR
PartsContainer
prepare_compiletime_parts
(
basic_string_view
<
Char
>
format
)
{
using
collector
=
compiletime_prepared_parts_collector
<
PartsContainer
>
;
PartsContainer
parts
;
collector
c
(
parts
);
internal
::
parse_format_string
<
/*IS_CONSTEXPR=*/
true
>
(
format
,
format_preparation_handler
<
Char
,
collector
>
(
format
,
c
));
return
parts
;
}
template
<
typename
PartsContainer
>
class
runtime_parts_provider
{
public:
runtime_parts_provider
()
=
delete
;
template
<
typename
Char
>
runtime_parts_provider
(
basic_string_view
<
Char
>
format
)
:
parts_
(
prepare_parts
<
PartsContainer
>
(
format
))
{}
const
PartsContainer
&
parts
()
const
{
return
parts_
;
}
private:
PartsContainer
parts_
;
};
template
<
typename
Format
,
typename
PartsContainer
>
struct
compiletime_parts_provider
{
compiletime_parts_provider
()
=
delete
;
template
<
typename
Char
>
FMT_CONSTEXPR
compiletime_parts_provider
(
basic_string_view
<
Char
>
)
{}
const
PartsContainer
&
parts
()
const
{
static
FMT_CONSTEXPR_DECL
const
PartsContainer
prepared_parts
=
prepare_compiletime_parts
<
PartsContainer
>
(
internal
::
to_string_view
(
Format
{}));
return
prepared_parts
;
}
};
}
// namespace internal
#if FMT_USE_CONSTEXPR
template
<
typename
...
Args
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
FMT_CONSTEXPR
auto
compile
(
S
format_str
)
->
internal
::
prepared_format
<
S
,
internal
::
compiletime_parts_provider
<
S
,
typename
internal
::
compiletime_prepared_parts_type_provider
<
S
>::
type
>
,
Args
...
>
{
return
format_str
;
}
#endif
template
<
typename
...
Args
,
typename
Char
,
size_t
N
>
auto
compile
(
const
Char
(
&
format_str
)[
N
])
->
internal
::
prepared_format
<
std
::
basic_string
<
Char
>
,
internal
::
runtime_parts_provider
<
std
::
vector
<
internal
::
format_part
<
Char
>>>
,
Args
...
>
{
return
std
::
basic_string
<
Char
>
(
format_str
,
N
-
1
);
}
template
<
typename
CompiledFormat
,
typename
...
Args
,
typename
Char
=
typename
CompiledFormat
::
char_type
>
std
::
basic_string
<
Char
>
format
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
using
range
=
internal
::
buffer_range
<
Char
>
;
using
context
=
buffer_context
<
Char
>
;
cf
.
template
vformat_to
<
range
,
context
>(
range
(
buffer
),
{
make_format_args
<
context
>
(
args
...)});
return
to_string
(
buffer
);
}
template
<
typename
OutputIt
,
typename
CompiledFormat
,
typename
...
Args
>
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
cf
.
template
vformat_to
<
range
,
context
>(
range
(
out
),
{
make_format_args
<
context
>
(
args
...)});
}
template
<
typename
OutputIt
,
typename
CompiledFormat
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_output_iterator
<
OutputIt
>
::
value
)
>
format_to_n_result
<
OutputIt
>
format_to_n
(
OutputIt
out
,
size_t
n
,
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
auto
it
=
format_to
(
internal
::
truncating_iterator
<
OutputIt
>
(
out
,
n
),
cf
,
args
...);
return
{
it
.
base
(),
it
.
count
()};
}
template
<
typename
CompiledFormat
,
typename
...
Args
>
std
::
size_t
formatted_size
(
const
CompiledFormat
&
cf
,
const
Args
&
...
args
)
{
return
fmt
::
format_to
(
internal
::
counting_iterator
<
typename
CompiledFormat
::
char_type
>
(),
cf
,
args
...)
.
count
();
}
FMT_END_NAMESPACE
#endif // FMT_COMPILE_H_
include/spdlog/fmt/bundled/core.h
View file @
e149433a
...
...
@@ -16,7 +16,7 @@
#include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION
503
00
#define FMT_VERSION
600
00
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
...
...
@@ -70,16 +70,6 @@
# define FMT_CONSTEXPR_DECL
#endif
#ifndef FMT_USE_CONSTEXPR11
# define FMT_USE_CONSTEXPR11 \
(FMT_USE_CONSTEXPR || FMT_GCC_VERSION >= 406 || FMT_MSC_VER >= 1900)
#endif
#if FMT_USE_CONSTEXPR11
# define FMT_CONSTEXPR11 constexpr
#else
# define FMT_CONSTEXPR11
#endif
#ifndef FMT_OVERRIDE
# if FMT_HAS_FEATURE(cxx_override) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
...
...
@@ -89,28 +79,6 @@
# endif
#endif
#if FMT_HAS_FEATURE(cxx_explicit_conversions) || \
FMT_GCC_VERSION >= 405 || FMT_MSC_VER >= 1800
# define FMT_USE_EXPLICIT 1
# define FMT_EXPLICIT explicit
#else
# define FMT_USE_EXPLICIT 0
# define FMT_EXPLICIT
#endif
#ifndef FMT_NULL
# if FMT_HAS_FEATURE(cxx_nullptr) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600
# define FMT_NULL nullptr
# define FMT_USE_NULLPTR 1
# else
# define FMT_NULL NULL
# endif
#endif
#ifndef FMT_USE_NULLPTR
# define FMT_USE_NULLPTR 0
#endif
// Check if exceptions are disabled.
#ifndef FMT_EXCEPTIONS
# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
...
...
@@ -143,16 +111,45 @@
# endif
#endif
// [[noreturn]] is disabled on MSVC because of bogus unreachable code warnings.
#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
#endif
#ifndef FMT_DEPRECATED
# if (FMT_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \
FMT_MSC_VER >= 1900
# define FMT_DEPRECATED [[deprecated]]
# else
# if defined(__GNUC__) || defined(__clang__)
# define FMT_DEPRECATED __attribute__((deprecated))
# elif FMT_MSC_VER
# define FMT_DEPRECATED __declspec(deprecated)
# else
# define FMT_DEPRECATED
/* deprecated */
# endif
# endif
#endif
#ifndef FMT_BEGIN_NAMESPACE
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
FMT_MSC_VER >= 1900
# define FMT_INLINE_NAMESPACE inline namespace
# define FMT_END_NAMESPACE }}
# define FMT_END_NAMESPACE \
} \
}
# else
# define FMT_INLINE_NAMESPACE namespace
# define FMT_END_NAMESPACE } using namespace v5; }
# define FMT_END_NAMESPACE \
} \
using namespace v6; \
}
# endif
# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 {
# define FMT_BEGIN_NAMESPACE \
namespace fmt { \
FMT_INLINE_NAMESPACE v6 {
#endif
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
...
...
@@ -160,11 +157,21 @@
# define FMT_API __declspec(dllexport)
# elif defined(FMT_SHARED)
# define FMT_API __declspec(dllimport)
# define FMT_EXTERN_TEMPLATE_API FMT_API
# endif
#endif
#ifndef FMT_API
# define FMT_API
#endif
#ifndef FMT_EXTERN_TEMPLATE_API
# define FMT_EXTERN_TEMPLATE_API
#endif
#ifndef FMT_HEADER_ONLY
# define FMT_EXTERN extern
#else
# define FMT_EXTERN
#endif
#ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message)
...
...
@@ -175,33 +182,45 @@
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
# include <string_view>
#
define FMT_STRING_VIEW std::basic_string_view
#elif FMT_HAS_INCLUDE(
<experimental/string_view>
) && __cplusplus >= 201402L
#
define FMT_USE_STRING_VIEW
#elif FMT_HAS_INCLUDE(
"experimental/string_view"
) && __cplusplus >= 201402L
# include <experimental/string_view>
# define FMT_STRING_VIEW std::experimental::basic_string_view
#endif
// std::result_of is defined in <functional> in gcc 4.4.
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
# include <functional>
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif
FMT_BEGIN_NAMESPACE
namespace
internal
{
// An implementation of declval for pre-C++11 compilers such as gcc 4.
// Implementations of enable_if_t and other types for pre-C++14 systems.
template
<
bool
B
,
class
T
=
void
>
using
enable_if_t
=
typename
std
::
enable_if
<
B
,
T
>::
type
;
template
<
bool
B
,
class
T
,
class
F
>
using
conditional_t
=
typename
std
::
conditional
<
B
,
T
,
F
>::
type
;
template
<
bool
B
>
using
bool_constant
=
std
::
integral_constant
<
bool
,
B
>
;
template
<
typename
T
>
using
remove_reference_t
=
typename
std
::
remove_reference
<
T
>::
type
;
template
<
typename
T
>
typename
std
::
add_rvalue_reference
<
T
>::
type
declval
()
FMT_NOEXCEPT
;
using
remove_const_t
=
typename
std
::
remove_const
<
T
>::
type
;
template
<
typename
>
struct
result_of
;
struct
monostate
{};
template
<
typename
F
,
typename
...
Args
>
struct
result_of
<
F
(
Args
...)
>
{
// A workaround for gcc 4.4 that doesn't allow F to be a reference.
typedef
typename
std
::
result_of
<
typename
std
::
remove_reference
<
F
>::
type
(
Args
...)
>::
type
type
;
};
// An enable_if helper to be used in template parameters which results in much
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
namespace
internal
{
// 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
;
};
#if defined(FMT_USE_STRING_VIEW)
template
<
typename
Char
>
using
std_string_view
=
std
::
basic_string_view
<
Char
>
;
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
template
<
typename
Char
>
using
std_string_view
=
std
::
experimental
::
basic_string_view
<
Char
>
;
#else
template
<
typename
T
>
struct
std_string_view
{};
#endif
// Casts nonnegative integer to unsigned.
template
<
typename
Int
>
...
...
@@ -209,135 +228,10 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
FMT_ASSERT
(
value
>=
0
,
"negative value"
);
return
static_cast
<
typename
std
::
make_unsigned
<
Int
>::
type
>
(
value
);
}
/** A contiguous memory buffer with an optional growing ability. */
template
<
typename
T
>
class
basic_buffer
{
private:
basic_buffer
(
const
basic_buffer
&
)
=
delete
;
void
operator
=
(
const
basic_buffer
&
)
=
delete
;
T
*
ptr_
;
std
::
size_t
size_
;
std
::
size_t
capacity_
;
protected:
// Don't initialize ptr_ since it is not accessed to save a few cycles.
basic_buffer
(
std
::
size_t
sz
)
FMT_NOEXCEPT
:
size_
(
sz
),
capacity_
(
sz
)
{}
basic_buffer
(
T
*
p
=
FMT_NULL
,
std
::
size_t
sz
=
0
,
std
::
size_t
cap
=
0
)
FMT_NOEXCEPT:
ptr_
(
p
),
size_
(
sz
),
capacity_
(
cap
)
{}
/** Sets the buffer data and capacity. */
void
set
(
T
*
buf_data
,
std
::
size_t
buf_capacity
)
FMT_NOEXCEPT
{
ptr_
=
buf_data
;
capacity_
=
buf_capacity
;
}
/** Increases the buffer capacity to hold at least *capacity* elements. */
virtual
void
grow
(
std
::
size_t
capacity
)
=
0
;
public:
typedef
T
value_type
;
typedef
const
T
&
const_reference
;
virtual
~
basic_buffer
()
{}
T
*
begin
()
FMT_NOEXCEPT
{
return
ptr_
;
}
T
*
end
()
FMT_NOEXCEPT
{
return
ptr_
+
size_
;
}
/** Returns the size of this buffer. */
std
::
size_t
size
()
const
FMT_NOEXCEPT
{
return
size_
;
}
/** Returns the capacity of this buffer. */
std
::
size_t
capacity
()
const
FMT_NOEXCEPT
{
return
capacity_
;
}
/** Returns a pointer to the buffer data. */
T
*
data
()
FMT_NOEXCEPT
{
return
ptr_
;
}
/** Returns a pointer to the buffer data. */
const
T
*
data
()
const
FMT_NOEXCEPT
{
return
ptr_
;
}
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void
resize
(
std
::
size_t
new_size
)
{
reserve
(
new_size
);
size_
=
new_size
;
}
/** Clears this buffer. */
void
clear
()
{
size_
=
0
;
}
/** Reserves space to store at least *capacity* elements. */
void
reserve
(
std
::
size_t
new_capacity
)
{
if
(
new_capacity
>
capacity_
)
grow
(
new_capacity
);
}
void
push_back
(
const
T
&
value
)
{
reserve
(
size_
+
1
);
ptr_
[
size_
++
]
=
value
;
}
/** Appends data to the end of the buffer. */
template
<
typename
U
>
void
append
(
const
U
*
begin
,
const
U
*
end
);
T
&
operator
[](
std
::
size_t
index
)
{
return
ptr_
[
index
];
}
const
T
&
operator
[](
std
::
size_t
index
)
const
{
return
ptr_
[
index
];
}
};
typedef
basic_buffer
<
char
>
buffer
;
typedef
basic_buffer
<
wchar_t
>
wbuffer
;
// A container-backed buffer.
template
<
typename
Container
>
class
container_buffer
:
public
basic_buffer
<
typename
Container
::
value_type
>
{
private:
Container
&
container_
;
protected:
void
grow
(
std
::
size_t
capacity
)
FMT_OVERRIDE
{
container_
.
resize
(
capacity
);
this
->
set
(
&
container_
[
0
],
capacity
);
}
public:
explicit
container_buffer
(
Container
&
c
)
:
basic_buffer
<
typename
Container
::
value_type
>
(
c
.
size
()),
container_
(
c
)
{}
};
// Extracts a reference to the container from back_insert_iterator.
template
<
typename
Container
>
inline
Container
&
get_container
(
std
::
back_insert_iterator
<
Container
>
it
)
{
typedef
std
::
back_insert_iterator
<
Container
>
bi_iterator
;
struct
accessor
:
bi_iterator
{
accessor
(
bi_iterator
iter
)
:
bi_iterator
(
iter
)
{}
using
bi_iterator
::
container
;
};
return
*
accessor
(
it
).
container
;
}
struct
error_handler
{
FMT_CONSTEXPR
error_handler
()
{}
FMT_CONSTEXPR
error_handler
(
const
error_handler
&
)
{}
// This function is intentionally not constexpr to give a compile-time error.
FMT_API
void
on_error
(
const
char
*
message
);
};
template
<
typename
T
>
struct
no_formatter_error
:
std
::
false_type
{};
}
// namespace internal
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 405
template
<
typename
...
T
>
struct
is_constructible
:
std
::
false_type
{};
#else
template
<
typename
...
T
>
struct
is_constructible
:
std
::
is_constructible
<
T
...
>
{};
#endif
template
<
typename
...
Ts
>
using
void_t
=
typename
internal
::
void_t_impl
<
Ts
...
>::
type
;
/**
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
...
...
@@ -346,21 +240,21 @@ struct is_constructible : std::is_constructible<T...> {};
compiled with a different ``-std`` option than the client code (which is not
recommended).
*/
template
<
typename
Char
>
class
basic_string_view
{
template
<
typename
Char
>
class
basic_string_view
{
private:
const
Char
*
data_
;
const
Char
*
data_
;
size_t
size_
;
public:
typedef
Char
char_type
;
typedef
const
Char
*
iterator
;
using
char_type
=
Char
;
using
iterator
=
const
Char
*
;
FMT_CONSTEXPR
basic_string_view
()
FMT_NOEXCEPT
:
data_
(
FMT_NULL
),
size_
(
0
)
{}
FMT_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
:
data_
(
s
),
size_
(
count
)
{}
FMT_CONSTEXPR
basic_string_view
(
const
Char
*
s
,
size_t
count
)
FMT_NOEXCEPT
:
data_
(
s
),
size_
(
count
)
{}
/**
\rst
...
...
@@ -368,22 +262,23 @@ class basic_string_view {
the size with ``std::char_traits<Char>::length``.
\endrst
*/
basic_string_view
(
const
Char
*
s
)
basic_string_view
(
const
Char
*
s
)
:
data_
(
s
),
size_
(
std
::
char_traits
<
Char
>::
length
(
s
))
{}
/** Constructs a string reference from a ``std::basic_string`` object. */
template
<
typename
Alloc
>
FMT_CONSTEXPR
basic_string_view
(
const
std
::
basic_string
<
Char
,
Alloc
>
&
s
)
FMT_NOEXCEPT
:
data_
(
s
.
data
()),
size_
(
s
.
size
())
{}
FMT_CONSTEXPR
basic_string_view
(
const
std
::
basic_string
<
Char
,
Alloc
>&
s
)
FMT_NOEXCEPT
:
data_
(
s
.
data
()),
size_
(
s
.
size
())
{}
#ifdef FMT_STRING_VIEW
FMT_CONSTEXPR
basic_string_view
(
FMT_STRING_VIEW
<
Char
>
s
)
FMT_NOEXCEPT
:
data_
(
s
.
data
()),
size_
(
s
.
size
())
{}
#endif
template
<
typename
S
,
FMT_ENABLE_IF
(
std
::
is_same
<
S
,
internal
::
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_
;
}
FMT_CONSTEXPR
const
Char
*
data
()
const
{
return
data_
;
}
/** Returns the string size. */
FMT_CONSTEXPR
size_t
size
()
const
{
return
size_
;
}
...
...
@@ -425,47 +320,60 @@ class basic_string_view {
}
};
typedef
basic_string_view
<
char
>
string_view
;
typedef
basic_string_view
<
wchar_t
>
wstring_view
;
using
string_view
=
basic_string_view
<
char
>
;
using
wstring_view
=
basic_string_view
<
wchar_t
>
;
#ifndef __cpp_char8_t
// A UTF-8 code unit type.
enum
char8_t
:
unsigned
char
{};
#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
<
char8_t
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
char16_t
>
:
std
::
true_type
{};
template
<
>
struct
is_char
<
char32_t
>
:
std
::
true_type
{};
/**
\rst
The function ``to_string_view`` adapts non-intrusively any kind of string or
string-like type if the user provides a (possibly templated) overload of
``to_string_view`` which takes an instance of the string class
``StringType<Char>`` and returns a ``fmt::basic_string_view<Char>``.
The conversion function must live in the very same namespace as
``StringType<Char>`` to be picked up by ADL. Non-templated string types
like f.e. QString must return a ``basic_string_view`` with a fixed matching
char type.
Returns a string view of `s`. In order to add custom string type support to
{fmt} provide an overload of `to_string_view` for it in the same namespace as
the type for the argument-dependent lookup to work.
**Example**::
namespace my_ns {
inline string_view to_string_view(const my_string
&
s) {
inline string_view to_string_view(const my_string
&
s) {
return {s.data(), s.length()};
}
}
std::string message = fmt::format(my_string("The answer is {}"), 42);
\endrst
*/
template
<
typename
Char
>
inline
basic_string_view
<
Char
>
to_string_view
(
basic_string_view
<
Char
>
s
)
{
return
s
;
}
template
<
typename
Char
,
FMT_ENABLE_IF
(
is_char
<
Char
>
::
value
)
>
inline
basic_string_view
<
Char
>
to_string_view
(
const
Char
*
s
)
{
return
s
;
}
template
<
typename
Char
>
inline
basic_string_view
<
Char
>
to_string_view
(
const
std
::
basic_string
<
Char
>
&
s
)
{
return
s
;
}
template
<
typename
Char
,
typename
Traits
,
typename
Allocator
>
inline
basic_string_view
<
Char
>
to_string_view
(
const
std
::
basic_string
<
Char
,
Traits
,
Allocator
>&
s
)
{
return
{
s
.
data
(),
s
.
size
()};
}
template
<
typename
Char
>
inline
basic_string_view
<
Char
>
to_string_view
(
const
Char
*
s
)
{
return
s
;
}
inline
basic_string_view
<
Char
>
to_string_view
(
basic_string_view
<
Char
>
s
)
{
return
s
;
}
#ifdef FMT_STRING_VIEW
template
<
typename
Char
>
inline
basic_string_view
<
Char
>
to_string_view
(
FMT_STRING_VIEW
<
Char
>
s
)
{
return
s
;
}
#endif
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
)
{
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).
...
...
@@ -474,332 +382,504 @@ struct compile_string {};
template
<
typename
S
>
struct
is_compile_string
:
std
::
is_base_of
<
compile_string
,
S
>
{};
template
<
typename
S
,
typename
Enable
=
typename
std
::
enable_if
<
is_compile_string
<
S
>
::
value
>::
type
>
FMT_CONSTEXPR
basic_string_view
<
typename
S
::
char_type
>
to_string_view
(
const
S
&
s
)
{
return
s
;
}
template
<
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
constexpr
basic_string_view
<
typename
S
::
char_type
>
to_string_view
(
const
S
&
s
)
{
return
s
;
}
template
<
typename
Context
>
class
basic_format_arg
;
namespace
internal
{
void
to_string_view
(...);
using
fmt
::
v6
::
to_string_view
;
template
<
typename
Context
>
class
basic_format_args
;
// Specifies whether S is a string type convertible to fmt::basic_string_view.
// It should be a constexpr function but MSVC 2017 fails to compile it in
// enable_if and MSVC 2015 fails to compile it as an alias template.
template
<
typename
S
>
struct
is_string
:
std
::
is_class
<
decltype
(
to_string_view
(
std
::
declval
<
S
>
()))
>
{
};
template
<
typename
S
,
typename
=
void
>
struct
char_t_impl
{};
template
<
typename
S
>
struct
char_t_impl
<
S
,
enable_if_t
<
is_string
<
S
>::
value
>>
{
using
result
=
decltype
(
to_string_view
(
std
::
declval
<
S
>
()));
using
type
=
typename
result
::
char_type
;
};
struct
error_handler
{
FMT_CONSTEXPR
error_handler
()
{}
FMT_CONSTEXPR
error_handler
(
const
error_handler
&
)
{}
// This function is intentionally not constexpr to give a compile-time error.
FMT_NORETURN
FMT_API
void
on_error
(
const
char
*
message
);
};
}
// namespace internal
/** String's character type. */
template
<
typename
S
>
using
char_t
=
typename
internal
::
char_t_impl
<
S
>::
type
;
// Parsing context consisting of a format string range being parsed and an
// argument counter for automatic indexing.
template
<
typename
Char
,
typename
ErrorHandler
=
internal
::
error_handler
>
class
basic_parse_context
:
private
ErrorHandler
{
private:
basic_string_view
<
Char
>
format_str_
;
int
next_arg_id_
;
public:
using
char_type
=
Char
;
using
iterator
=
typename
basic_string_view
<
Char
>::
iterator
;
explicit
FMT_CONSTEXPR
basic_parse_context
(
basic_string_view
<
Char
>
format_str
,
ErrorHandler
eh
=
ErrorHandler
())
:
ErrorHandler
(
eh
),
format_str_
(
format_str
),
next_arg_id_
(
0
)
{}
// Returns an iterator to the beginning of the format string range being
// parsed.
FMT_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
();
}
// Advances the begin iterator to ``it``.
FMT_CONSTEXPR
void
advance_to
(
iterator
it
)
{
format_str_
.
remove_prefix
(
internal
::
to_unsigned
(
it
-
begin
()));
}
// Returns the next argument index.
FMT_CONSTEXPR
int
next_arg_id
()
{
if
(
next_arg_id_
>=
0
)
return
next_arg_id_
++
;
on_error
(
"cannot switch from manual to automatic argument indexing"
);
return
0
;
}
FMT_CONSTEXPR
bool
check_arg_id
(
int
)
{
if
(
next_arg_id_
>
0
)
{
on_error
(
"cannot switch from automatic to manual argument indexing"
);
return
false
;
}
next_arg_id_
=
-
1
;
return
true
;
}
FMT_CONSTEXPR
void
check_arg_id
(
basic_string_view
<
Char
>
)
{}
FMT_CONSTEXPR
void
on_error
(
const
char
*
message
)
{
ErrorHandler
::
on_error
(
message
);
}
FMT_CONSTEXPR
ErrorHandler
error_handler
()
const
{
return
*
this
;
}
};
using
format_parse_context
=
basic_parse_context
<
char
>
;
using
wformat_parse_context
=
basic_parse_context
<
wchar_t
>
;
using
parse_context
FMT_DEPRECATED
=
basic_parse_context
<
char
>
;
using
wparse_context
FMT_DEPRECATED
=
basic_parse_context
<
wchar_t
>
;
template
<
typename
Context
>
class
basic_format_arg
;
template
<
typename
Context
>
class
basic_format_args
;
// A formatter for objects of type T.
template
<
typename
T
,
typename
Char
=
char
,
typename
Enable
=
void
>
struct
formatter
{
static_assert
(
internal
::
no_formatter_error
<
T
>::
value
,
"don't know how to format the type, include fmt/ostream.h if it provides "
"an operator<< that should be used"
);
// The following functions are not defined intentionally.
template
<
typename
ParseContext
>
typename
ParseContext
::
iterator
parse
(
ParseContext
&
);
template
<
typename
FormatContext
>
auto
format
(
const
T
&
val
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
());
// A deleted default constructor indicates a disabled formatter.
formatter
()
=
delete
;
};
template
<
typename
T
,
typename
Char
,
typename
Enable
=
void
>
struct
convert_to_int
:
std
::
integral_constant
<
bool
,
!
std
::
is_arithmetic
<
T
>::
value
&&
std
::
is_convertible
<
T
,
int
>::
value
>
{};
struct
FMT_DEPRECATED
convert_to_int
:
bool_constant
<!
std
::
is_arithmetic
<
T
>::
value
&&
std
::
is_convertible
<
T
,
int
>::
value
>
{};
namespace
internal
{
struct
dummy_string_view
{
typedef
void
char_type
;
};
dummy_string_view
to_string_view
(...);
using
fmt
::
v5
::
to_string_view
;
// 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
>
>
;
// Specifies whether S is a string type convertible to fmt::basic_string_view.
template
<
typename
S
>
struct
is_string
:
std
::
integral_constant
<
bool
,
!
std
::
is_same
<
dummy_string_view
,
decltype
(
to_string_view
(
declval
<
S
>
()))
>::
value
>
{};
/** A contiguous memory buffer with an optional growing ability. */
template
<
typename
T
>
class
buffer
{
private:
buffer
(
const
buffer
&
)
=
delete
;
void
operator
=
(
const
buffer
&
)
=
delete
;
template
<
typename
S
>
struct
char_t
{
typedef
decltype
(
to_string_view
(
declval
<
S
>
()))
result
;
typedef
typename
result
::
char_type
type
;
T
*
ptr_
;
std
::
size_t
size_
;
std
::
size_t
capacity_
;
protected:
// Don't initialize ptr_ since it is not accessed to save a few cycles.
buffer
(
std
::
size_t
sz
)
FMT_NOEXCEPT
:
size_
(
sz
),
capacity_
(
sz
)
{}
buffer
(
T
*
p
=
nullptr
,
std
::
size_t
sz
=
0
,
std
::
size_t
cap
=
0
)
FMT_NOEXCEPT
:
ptr_
(
p
),
size_
(
sz
),
capacity_
(
cap
)
{}
/** Sets the buffer data and capacity. */
void
set
(
T
*
buf_data
,
std
::
size_t
buf_capacity
)
FMT_NOEXCEPT
{
ptr_
=
buf_data
;
capacity_
=
buf_capacity
;
}
/** Increases the buffer capacity to hold at least *capacity* elements. */
virtual
void
grow
(
std
::
size_t
capacity
)
=
0
;
public:
using
value_type
=
T
;
using
const_reference
=
const
T
&
;
virtual
~
buffer
()
{}
T
*
begin
()
FMT_NOEXCEPT
{
return
ptr_
;
}
T
*
end
()
FMT_NOEXCEPT
{
return
ptr_
+
size_
;
}
/** Returns the size of this buffer. */
std
::
size_t
size
()
const
FMT_NOEXCEPT
{
return
size_
;
}
/** Returns the capacity of this buffer. */
std
::
size_t
capacity
()
const
FMT_NOEXCEPT
{
return
capacity_
;
}
/** Returns a pointer to the buffer data. */
T
*
data
()
FMT_NOEXCEPT
{
return
ptr_
;
}
/** Returns a pointer to the buffer data. */
const
T
*
data
()
const
FMT_NOEXCEPT
{
return
ptr_
;
}
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void
resize
(
std
::
size_t
new_size
)
{
reserve
(
new_size
);
size_
=
new_size
;
}
/** Clears this buffer. */
void
clear
()
{
size_
=
0
;
}
/** Reserves space to store at least *capacity* elements. */
void
reserve
(
std
::
size_t
new_capacity
)
{
if
(
new_capacity
>
capacity_
)
grow
(
new_capacity
);
}
void
push_back
(
const
T
&
value
)
{
reserve
(
size_
+
1
);
ptr_
[
size_
++
]
=
value
;
}
/** Appends data to the end of the buffer. */
template
<
typename
U
>
void
append
(
const
U
*
begin
,
const
U
*
end
);
T
&
operator
[](
std
::
size_t
index
)
{
return
ptr_
[
index
];
}
const
T
&
operator
[](
std
::
size_t
index
)
const
{
return
ptr_
[
index
];
}
};
template
<
typename
Char
>
struct
named_arg_base
;
// A container-backed buffer.
template
<
typename
Container
>
class
container_buffer
:
public
buffer
<
typename
Container
::
value_type
>
{
private:
Container
&
container_
;
template
<
typename
T
,
typename
Char
>
struct
named_arg
;
protected:
void
grow
(
std
::
size_t
capacity
)
FMT_OVERRIDE
{
container_
.
resize
(
capacity
);
this
->
set
(
&
container_
[
0
],
capacity
);
}
public:
explicit
container_buffer
(
Container
&
c
)
:
buffer
<
typename
Container
::
value_type
>
(
c
.
size
()),
container_
(
c
)
{}
};
// Extracts a reference to the container from back_insert_iterator.
template
<
typename
Container
>
inline
Container
&
get_container
(
std
::
back_insert_iterator
<
Container
>
it
)
{
using
bi_iterator
=
std
::
back_insert_iterator
<
Container
>
;
struct
accessor
:
bi_iterator
{
accessor
(
bi_iterator
iter
)
:
bi_iterator
(
iter
)
{}
using
bi_iterator
::
container
;
};
return
*
accessor
(
it
).
container
;
}
template
<
typename
T
,
typename
Char
=
char
,
typename
Enable
=
void
>
struct
fallback_formatter
{
fallback_formatter
()
=
delete
;
};
// Specifies if T has an enabled fallback_formatter specialization.
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
;
enum
type
{
none_type
,
named_arg_type
,
none_type
,
named_arg_type
,
// Integer types should go first,
int_type
,
uint_type
,
long_long_type
,
ulong_long_type
,
bool_type
,
char_type
,
int_type
,
uint_type
,
long_long_type
,
ulong_long_type
,
bool_type
,
char_type
,
last_integer_type
=
char_type
,
// followed by floating-point types.
double_type
,
long_double_type
,
last_numeric_type
=
long_double_type
,
cstring_type
,
string_type
,
pointer_type
,
custom_type
double_type
,
long_double_type
,
last_numeric_type
=
long_double_type
,
cstring_type
,
string_type
,
pointer_type
,
custom_type
};
// Maps core type T to the corresponding type enum constant.
template
<
typename
T
,
typename
Char
>
struct
type_constant
:
std
::
integral_constant
<
type
,
custom_type
>
{};
#define FMT_TYPE_CONSTANT(Type, constant) \
template <typename Char> \
struct type_constant<Type, Char> : std::integral_constant<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
);
FMT_TYPE_CONSTANT
(
unsigned
long
long
,
ulong_long_type
);
FMT_TYPE_CONSTANT
(
bool
,
bool_type
);
FMT_TYPE_CONSTANT
(
Char
,
char_type
);
FMT_TYPE_CONSTANT
(
double
,
double_type
);
FMT_TYPE_CONSTANT
(
long
double
,
long_double_type
);
FMT_TYPE_CONSTANT
(
const
Char
*
,
cstring_type
);
FMT_TYPE_CONSTANT
(
basic_string_view
<
Char
>
,
string_type
);
FMT_TYPE_CONSTANT
(
const
void
*
,
pointer_type
);
FMT_CONSTEXPR
bool
is_integral
(
type
t
)
{
FMT_ASSERT
(
t
!=
internal
::
named_arg_type
,
"invalid argument type"
);
return
t
>
internal
::
none_type
&&
t
<=
internal
::
last_integer_type
;
FMT_ASSERT
(
t
!=
named_arg_type
,
"invalid argument type"
);
return
t
>
none_type
&&
t
<=
last_integer_type
;
}
FMT_CONSTEXPR
bool
is_arithmetic
(
type
t
)
{
FMT_ASSERT
(
t
!=
internal
::
named_arg_type
,
"invalid argument type"
);
return
t
>
internal
::
none_type
&&
t
<=
internal
::
last_numeric_type
;
FMT_ASSERT
(
t
!=
named_arg_type
,
"invalid argument type"
);
return
t
>
none_type
&&
t
<=
last_numeric_type
;
}
template
<
typename
Char
>
struct
string_value
{
const
Char
*
value
;
template
<
typename
Char
>
struct
string_value
{
const
Char
*
data
;
std
::
size_t
size
;
};
template
<
typename
Context
>
struct
custom_value
{
const
void
*
value
;
void
(
*
format
)(
const
void
*
arg
,
Context
&
ctx
);
template
<
typename
Context
>
struct
custom_value
{
using
parse_context
=
basic_parse_context
<
typename
Context
::
char_type
>
;
const
void
*
value
;
void
(
*
format
)(
const
void
*
arg
,
parse_context
&
parse_ctx
,
Context
&
ctx
);
};
// A formatting argument value.
template
<
typename
Context
>
class
value
{
template
<
typename
Context
>
class
value
{
public:
typedef
typename
Context
::
char_type
char_type
;
using
char_type
=
typename
Context
::
char_type
;
union
{
int
int_value
;
unsigned
uint_value
;
long
long
long_long_value
;
unsigned
long
long
ulong_long_value
;
bool
bool_value
;
char_type
char_value
;
double
double_value
;
long
double
long_double_value
;
const
void
*
pointer
;
const
void
*
pointer
;
string_value
<
char_type
>
string
;
string_value
<
signed
char
>
sstring
;
string_value
<
unsigned
char
>
ustring
;
custom_value
<
Context
>
custom
;
const
named_arg_base
<
char_type
>*
named_arg
;
};
FMT_CONSTEXPR
value
(
int
val
=
0
)
:
int_value
(
val
)
{}
value
(
unsigned
val
)
{
uint_value
=
val
;
}
value
(
long
long
val
)
{
long_long_value
=
val
;
}
value
(
unsigned
long
long
val
)
{
ulong_long_value
=
val
;
}
value
(
double
val
)
{
double_value
=
val
;
}
value
(
long
double
val
)
{
long_double_value
=
val
;
}
value
(
const
char_type
*
val
)
{
string
.
value
=
val
;
}
value
(
const
signed
char
*
val
)
{
static_assert
(
std
::
is_same
<
char
,
char_type
>::
value
,
"incompatible string types"
);
sstring
.
value
=
val
;
}
value
(
const
unsigned
char
*
val
)
{
static_assert
(
std
::
is_same
<
char
,
char_type
>::
value
,
"incompatible string types"
);
ustring
.
value
=
val
;
}
FMT_CONSTEXPR
value
(
unsigned
val
)
:
uint_value
(
val
)
{}
value
(
long
long
val
)
:
long_long_value
(
val
)
{}
value
(
unsigned
long
long
val
)
:
ulong_long_value
(
val
)
{}
value
(
double
val
)
:
double_value
(
val
)
{}
value
(
long
double
val
)
:
long_double_value
(
val
)
{}
value
(
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
)
{
string
.
value
=
val
.
data
();
string
.
data
=
val
.
data
();
string
.
size
=
val
.
size
();
}
value
(
const
void
*
val
)
{
pointer
=
val
;
}
value
(
const
void
*
val
)
:
pointer
(
val
)
{
}
template
<
typename
T
>
explicit
value
(
const
T
&
val
)
{
template
<
typename
T
>
value
(
const
T
&
val
)
{
custom
.
value
=
&
val
;
custom
.
format
=
&
format_custom_arg
<
T
>
;
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
// `printf_formatter<T>` for `printf`.
custom
.
format
=
format_custom_arg
<
T
,
conditional_t
<
has_formatter
<
T
,
Context
>::
value
,
typename
Context
::
template
formatter_type
<
T
>,
fallback_formatter
<
T
,
char_type
>>>
;
}
const
named_arg_base
<
char_type
>
&
as_named_arg
()
{
return
*
static_cast
<
const
named_arg_base
<
char_type
>*>
(
pointer
);
}
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
>
static
void
format_custom_arg
(
const
void
*
arg
,
Context
&
ctx
)
{
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
// `printf_formatter<T>` for `printf`.
typename
Context
::
template
formatter_type
<
T
>
::
type
f
;
auto
&&
parse_ctx
=
ctx
.
parse_context
();
template
<
typename
T
,
typename
Formatter
>
static
void
format_custom_arg
(
const
void
*
arg
,
basic_parse_context
<
char_type
>&
parse_ctx
,
Context
&
ctx
)
{
Formatter
f
;
parse_ctx
.
advance_to
(
f
.
parse
(
parse_ctx
));
ctx
.
advance_to
(
f
.
format
(
*
static_cast
<
const
T
*>
(
arg
),
ctx
));
}
};
// Value initializer used to delay conversion to value and reduce memory churn.
template
<
typename
Context
,
typename
T
,
type
TYPE
>
struct
init
{
T
val
;
static
const
type
type_tag
=
TYPE
;
FMT_CONSTEXPR
init
(
const
T
&
v
)
:
val
(
v
)
{}
FMT_CONSTEXPR
operator
value
<
Context
>
()
const
{
return
value
<
Context
>
(
val
);
}
};
template
<
typename
Context
,
typename
T
>
FMT_CONSTEXPR
basic_format_arg
<
Context
>
make_arg
(
const
T
&
value
);
FMT_CONSTEXPR
basic_format_arg
<
Context
>
make_arg
(
const
T
&
value
);
#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \
template <typename C> \
FMT_CONSTEXPR init<C, ValueType, TAG> make_value(ArgType val) { \
return static_cast<ValueType>(val); \
// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
enum
{
long_short
=
sizeof
(
long
)
==
sizeof
(
int
)
};
using
long_type
=
conditional_t
<
long_short
,
int
,
long
long
>
;
using
ulong_type
=
conditional_t
<
long_short
,
unsigned
,
unsigned
long
long
>
;
// Maps formatting arguments to core types.
template
<
typename
Context
>
struct
arg_mapper
{
using
char_type
=
typename
Context
::
char_type
;
FMT_CONSTEXPR
int
map
(
signed
char
val
)
{
return
val
;
}
FMT_CONSTEXPR
unsigned
map
(
unsigned
char
val
)
{
return
val
;
}
FMT_CONSTEXPR
int
map
(
short
val
)
{
return
val
;
}
FMT_CONSTEXPR
unsigned
map
(
unsigned
short
val
)
{
return
val
;
}
FMT_CONSTEXPR
int
map
(
int
val
)
{
return
val
;
}
FMT_CONSTEXPR
unsigned
map
(
unsigned
val
)
{
return
val
;
}
FMT_CONSTEXPR
long_type
map
(
long
val
)
{
return
val
;
}
FMT_CONSTEXPR
ulong_type
map
(
unsigned
long
val
)
{
return
val
;
}
FMT_CONSTEXPR
long
long
map
(
long
long
val
)
{
return
val
;
}
FMT_CONSTEXPR
unsigned
long
long
map
(
unsigned
long
long
val
)
{
return
val
;
}
FMT_CONSTEXPR
bool
map
(
bool
val
)
{
return
val
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
is_char
<
T
>
::
value
)
>
FMT_CONSTEXPR
char_type
map
(
T
val
)
{
static_assert
(
std
::
is_same
<
T
,
char
>::
value
||
std
::
is_same
<
T
,
char_type
>::
value
,
"mixing character types is disallowed"
);
return
val
;
}
#define FMT_MAKE_VALUE_SAME(TAG, Type) \
template <typename C> \
FMT_CONSTEXPR
init<C, Type, TAG> make_value(Typ
e val) { return val; }
FMT_CONSTEXPR
double
map
(
float
val
)
{
return
static_cast
<
double
>
(
val
);
}
FMT_CONSTEXPR
double
map
(
double
val
)
{
return
val
;
}
FMT_CONSTEXPR
long
double
map
(
long
doubl
e
val
)
{
return
val
;
}
FMT_MAKE_VALUE
(
bool_type
,
bool
,
int
)
FMT_MAKE_VALUE
(
int_type
,
short
,
int
)
FMT_MAKE_VALUE
(
uint_type
,
unsigned
short
,
unsigned
)
FMT_MAKE_VALUE_SAME
(
int_type
,
int
)
FMT_MAKE_VALUE_SAME
(
uint_type
,
unsigned
)
// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
typedef
std
::
conditional
<
sizeof
(
long
)
==
sizeof
(
int
),
int
,
long
long
>::
type
long_type
;
FMT_MAKE_VALUE
(
(
sizeof
(
long
)
==
sizeof
(
int
)
?
int_type
:
long_long_type
),
long
,
long_type
)
typedef
std
::
conditional
<
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
),
unsigned
,
unsigned
long
long
>::
type
ulong_type
;
FMT_MAKE_VALUE
(
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)
?
uint_type
:
ulong_long_type
),
unsigned
long
,
ulong_type
)
FMT_MAKE_VALUE_SAME
(
long_long_type
,
long
long
)
FMT_MAKE_VALUE_SAME
(
ulong_long_type
,
unsigned
long
long
)
FMT_MAKE_VALUE
(
int_type
,
signed
char
,
int
)
FMT_MAKE_VALUE
(
uint_type
,
unsigned
char
,
unsigned
)
// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4.
template
<
typename
C
,
typename
Char
>
FMT_CONSTEXPR
typename
std
::
enable_if
<
std
::
is_same
<
typename
C
::
char_type
,
Char
>::
value
,
init
<
C
,
int
,
char_type
>>::
type
make_value
(
Char
val
)
{
return
val
;
}
template
<
typename
C
>
FMT_CONSTEXPR
typename
std
::
enable_if
<
!
std
::
is_same
<
typename
C
::
char_type
,
char
>::
value
,
init
<
C
,
int
,
char_type
>>::
type
make_value
(
char
val
)
{
return
val
;
}
FMT_MAKE_VALUE
(
double_type
,
float
,
double
)
FMT_MAKE_VALUE_SAME
(
double_type
,
double
)
FMT_MAKE_VALUE_SAME
(
long_double_type
,
long
double
)
// Formatting of wide strings into a narrow buffer and multibyte strings
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
FMT_MAKE_VALUE
(
cstring_type
,
typename
C
::
char_type
*
,
const
typename
C
::
char_type
*
)
FMT_MAKE_VALUE
(
cstring_type
,
const
typename
C
::
char_type
*
,
const
typename
C
::
char_type
*
)
FMT_MAKE_VALUE
(
cstring_type
,
signed
char
*
,
const
signed
char
*
)
FMT_MAKE_VALUE_SAME
(
cstring_type
,
const
signed
char
*
)
FMT_MAKE_VALUE
(
cstring_type
,
unsigned
char
*
,
const
unsigned
char
*
)
FMT_MAKE_VALUE_SAME
(
cstring_type
,
const
unsigned
char
*
)
FMT_MAKE_VALUE_SAME
(
string_type
,
basic_string_view
<
typename
C
::
char_type
>
)
FMT_MAKE_VALUE
(
string_type
,
typename
basic_string_view
<
typename
C
::
char_type
>::
type
,
basic_string_view
<
typename
C
::
char_type
>
)
FMT_MAKE_VALUE
(
string_type
,
const
std
::
basic_string
<
typename
C
::
char_type
>&
,
basic_string_view
<
typename
C
::
char_type
>
)
FMT_MAKE_VALUE
(
pointer_type
,
void
*
,
const
void
*
)
FMT_MAKE_VALUE_SAME
(
pointer_type
,
const
void
*
)
#if FMT_USE_NULLPTR
FMT_MAKE_VALUE
(
pointer_type
,
std
::
nullptr_t
,
const
void
*
)
#endif
FMT_CONSTEXPR
const
char_type
*
map
(
char_type
*
val
)
{
return
val
;
}
FMT_CONSTEXPR
const
char_type
*
map
(
const
char_type
*
val
)
{
return
val
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
is_string
<
T
>
::
value
)
>
FMT_CONSTEXPR
basic_string_view
<
char_type
>
map
(
const
T
&
val
)
{
static_assert
(
std
::
is_same
<
char_type
,
char_t
<
T
>>::
value
,
"mixing character types is disallowed"
);
return
to_string_view
(
val
);
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_constructible
<
basic_string_view
<
char_type
>,
T
>::
value
&&
!
is_string
<
T
>::
value
)
>
FMT_CONSTEXPR
basic_string_view
<
char_type
>
map
(
const
T
&
val
)
{
return
basic_string_view
<
char_type
>
(
val
);
}
FMT_CONSTEXPR
const
char
*
map
(
const
signed
char
*
val
)
{
static_assert
(
std
::
is_same
<
char_type
,
char
>::
value
,
"invalid string type"
);
return
reinterpret_cast
<
const
char
*>
(
val
);
}
FMT_CONSTEXPR
const
char
*
map
(
const
unsigned
char
*
val
)
{
static_assert
(
std
::
is_same
<
char_type
,
char
>::
value
,
"invalid string type"
);
return
reinterpret_cast
<
const
char
*>
(
val
);
}
// Formatting of arbitrary pointers is disallowed. If you want to output a
// pointer cast it to "void *" or "const void *". In particular, this forbids
// formatting of "[const] volatile char *" which is printed as bool by
// iostreams.
template
<
typename
C
,
typename
T
>
typename
std
::
enable_if
<!
std
::
is_same
<
T
,
typename
C
::
char_type
>::
value
>::
type
make_value
(
const
T
*
)
{
FMT_CONSTEXPR
const
void
*
map
(
void
*
val
)
{
return
val
;
}
FMT_CONSTEXPR
const
void
*
map
(
const
void
*
val
)
{
return
val
;
}
FMT_CONSTEXPR
const
void
*
map
(
std
::
nullptr_t
val
)
{
return
val
;
}
template
<
typename
T
>
FMT_CONSTEXPR
int
map
(
const
T
*
)
{
// Formatting of arbitrary pointers is disallowed. If you want to output
// a pointer cast it to "void *" or "const void *". In particular, this
// forbids formatting of "[const] volatile char *" which is printed as bool
// by iostreams.
static_assert
(
!
sizeof
(
T
),
"formatting of non-void pointers is disallowed"
);
}
return
0
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_enum
<
T
>
::
value
&&
!
has_formatter
<
T
,
Context
>::
value
&&
!
has_fallback_formatter
<
T
,
Context
>::
value
)
>
FMT_CONSTEXPR
int
map
(
const
T
&
val
)
{
return
static_cast
<
int
>
(
val
);
}
template
<
typename
T
,
FMT_ENABLE_IF
(
!
is_string
<
T
>
::
value
&&
!
is_char
<
T
>::
value
&&
(
has_formatter
<
T
,
Context
>::
value
||
has_fallback_formatter
<
T
,
Context
>::
value
))
>
FMT_CONSTEXPR
const
T
&
map
(
const
T
&
val
)
{
return
val
;
}
template
<
typename
C
,
typename
T
>
inline
typename
std
::
enable_if
<
std
::
is_enum
<
T
>::
value
&&
convert_to_int
<
T
,
typename
C
::
char_type
>::
value
,
init
<
C
,
int
,
int_type
>>::
type
make_value
(
const
T
&
val
)
{
return
static_cast
<
int
>
(
val
);
}
template
<
typename
C
,
typename
T
,
typename
Char
=
typename
C
::
char_type
>
inline
typename
std
::
enable_if
<
is_constructible
<
basic_string_view
<
Char
>
,
T
>::
value
&&
!
internal
::
is_string
<
T
>::
value
,
init
<
C
,
basic_string_view
<
Char
>
,
string_type
>>::
type
make_value
(
const
T
&
val
)
{
return
basic_string_view
<
Char
>
(
val
);
}
template
<
typename
C
,
typename
T
,
typename
Char
=
typename
C
::
char_type
>
inline
typename
std
::
enable_if
<
!
convert_to_int
<
T
,
Char
>::
value
&&
!
std
::
is_same
<
T
,
Char
>::
value
&&
!
std
::
is_convertible
<
T
,
basic_string_view
<
Char
>>::
value
&&
!
is_constructible
<
basic_string_view
<
Char
>
,
T
>::
value
&&
!
internal
::
is_string
<
T
>::
value
,
// Implicit conversion to std::string is not handled here because it's
// unsafe: https://github.com/fmtlib/fmt/issues/729
init
<
C
,
const
T
&
,
custom_type
>>::
type
make_value
(
const
T
&
val
)
{
return
val
;
}
template
<
typename
C
,
typename
T
>
init
<
C
,
const
void
*
,
named_arg_type
>
make_value
(
const
named_arg
<
T
,
typename
C
::
char_type
>
&
val
)
{
basic_format_arg
<
C
>
arg
=
make_arg
<
C
>
(
val
.
value
);
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
static_cast
<
const
void
*>
(
&
val
);
}
return
val
;
}
};
template
<
typename
C
,
typename
S
>
FMT_CONSTEXPR11
typename
std
::
enable_if
<
internal
::
is_string
<
S
>::
value
,
init
<
C
,
basic_string_view
<
typename
C
::
char_type
>
,
string_type
>>::
type
make_value
(
const
S
&
val
)
{
// Handle adapted strings.
static_assert
(
std
::
is_same
<
typename
C
::
char_type
,
typename
internal
::
char_t
<
S
>::
type
>::
value
,
"mismatch between char-types of context and argument"
);
return
to_string_view
(
val
);
}
// A type constant after applying arg_mapper<Context>.
template
<
typename
T
,
typename
Context
>
using
mapped_type_constant
=
type_constant
<
decltype
(
arg_mapper
<
Context
>
().
map
(
std
::
declval
<
T
>
())),
typename
Context
::
char_type
>
;
// Maximum number of arguments with packed types.
enum
{
max_packed_args
=
15
};
enum
:
unsigned
long
long
{
is_unpacked_bit
=
1ull
<<
63
};
template
<
typename
Context
>
class
arg_map
;
template
<
typename
Context
>
class
arg_map
;
}
// namespace internal
// A formatting argument. It is a trivially copyable/constructible type to
// allow storage in basic_memory_buffer.
template
<
typename
Context
>
class
basic_format_arg
{
template
<
typename
Context
>
class
basic_format_arg
{
private:
internal
::
value
<
Context
>
value_
;
internal
::
type
type_
;
template
<
typename
ContextType
,
typename
T
>
friend
FMT_CONSTEXPR
basic_format_arg
<
ContextType
>
internal
::
make_arg
(
const
T
&
value
);
friend
FMT_CONSTEXPR
basic_format_arg
<
ContextType
>
internal
::
make_arg
(
const
T
&
value
);
template
<
typename
Visitor
,
typename
Ctx
>
friend
FMT_CONSTEXPR
typename
internal
::
result_of
<
Visitor
(
int
)
>::
type
visit_format_arg
(
Visitor
&&
vis
,
const
basic_format_arg
<
Ctx
>
&
arg
);
friend
FMT_CONSTEXPR
auto
visit_format_arg
(
Visitor
&&
vis
,
const
basic_format_arg
<
Ctx
>&
arg
)
->
decltype
(
vis
(
0
));
friend
class
basic_format_args
<
Context
>
;
friend
class
internal
::
arg_map
<
Context
>
;
typedef
typename
Context
::
char_type
char_type
;
using
char_type
=
typename
Context
::
char_type
;
public:
class
handle
{
public:
explicit
handle
(
internal
::
custom_value
<
Context
>
custom
)
:
custom_
(
custom
)
{}
explicit
handle
(
internal
::
custom_value
<
Context
>
custom
)
:
custom_
(
custom
)
{}
void
format
(
Context
&
ctx
)
const
{
custom_
.
format
(
custom_
.
value
,
ctx
);
}
void
format
(
basic_parse_context
<
char_type
>&
parse_ctx
,
Context
&
ctx
)
const
{
custom_
.
format
(
custom_
.
value
,
parse_ctx
,
ctx
);
}
private:
internal
::
custom_value
<
Context
>
custom_
;
...
...
@@ -807,7 +887,7 @@ class basic_format_arg {
FMT_CONSTEXPR
basic_format_arg
()
:
type_
(
internal
::
none_type
)
{}
FMT_
EXPLICIT
operator
bool
()
const
FMT_NOEXCEPT
{
FMT_
CONSTEXPR
explicit
operator
bool
()
const
FMT_NOEXCEPT
{
return
type_
!=
internal
::
none_type
;
}
...
...
@@ -817,8 +897,6 @@ class basic_format_arg {
bool
is_arithmetic
()
const
{
return
internal
::
is_arithmetic
(
type_
);
}
};
struct
monostate
{};
/**
\rst
Visits an argument dispatching to the appropriate visit method based on
...
...
@@ -827,9 +905,10 @@ struct monostate {};
\endrst
*/
template
<
typename
Visitor
,
typename
Context
>
FMT_CONSTEXPR
typename
internal
::
result_of
<
Visitor
(
int
)
>::
type
visit_format_arg
(
Visitor
&&
vis
,
const
basic_format_arg
<
Context
>
&
arg
)
{
typedef
typename
Context
::
char_type
char_type
;
FMT_CONSTEXPR
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
internal
:
:
none_type
:
break
;
...
...
@@ -845,18 +924,18 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
case
internal
:
:
ulong_long_type
:
return
vis
(
arg
.
value_
.
ulong_long_value
);
case
internal
:
:
bool_type
:
return
vis
(
arg
.
value_
.
int_value
!=
0
);
return
vis
(
arg
.
value_
.
bool_value
);
case
internal
:
:
char_type
:
return
vis
(
static_cast
<
char_type
>
(
arg
.
value_
.
int_value
)
);
return
vis
(
arg
.
value_
.
char_value
);
case
internal
:
:
double_type
:
return
vis
(
arg
.
value_
.
double_value
);
case
internal
:
:
long_double_type
:
return
vis
(
arg
.
value_
.
long_double_value
);
case
internal
:
:
cstring_type
:
return
vis
(
arg
.
value_
.
string
.
value
);
return
vis
(
arg
.
value_
.
string
.
data
);
case
internal
:
:
string_type
:
return
vis
(
basic_string_view
<
char_type
>
(
arg
.
value_
.
string
.
value
,
arg
.
value_
.
string
.
size
));
return
vis
(
basic_string_view
<
char_type
>
(
arg
.
value_
.
string
.
data
,
arg
.
value_
.
string
.
size
));
case
internal
:
:
pointer_type
:
return
vis
(
arg
.
value_
.
pointer
);
case
internal
:
:
custom_type
:
...
...
@@ -865,104 +944,38 @@ FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
return
vis
(
monostate
());
}
// DEPRECATED!
template
<
typename
Visitor
,
typename
Context
>
FMT_CONSTEXPR
typename
internal
::
result_of
<
Visitor
(
int
)
>::
type
visit
(
Visitor
&&
vis
,
const
basic_format_arg
<
Context
>
&
arg
)
{
return
visit_format_arg
(
std
::
forward
<
Visitor
>
(
vis
),
arg
);
}
// Parsing context consisting of a format string range being parsed and an
// argument counter for automatic indexing.
template
<
typename
Char
,
typename
ErrorHandler
=
internal
::
error_handler
>
class
basic_parse_context
:
private
ErrorHandler
{
private:
basic_string_view
<
Char
>
format_str_
;
int
next_arg_id_
;
public:
typedef
Char
char_type
;
typedef
typename
basic_string_view
<
Char
>::
iterator
iterator
;
explicit
FMT_CONSTEXPR
basic_parse_context
(
basic_string_view
<
Char
>
format_str
,
ErrorHandler
eh
=
ErrorHandler
())
:
ErrorHandler
(
eh
),
format_str_
(
format_str
),
next_arg_id_
(
0
)
{}
// Returns an iterator to the beginning of the format string range being
// parsed.
FMT_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
();
}
// Advances the begin iterator to ``it``.
FMT_CONSTEXPR
void
advance_to
(
iterator
it
)
{
format_str_
.
remove_prefix
(
internal
::
to_unsigned
(
it
-
begin
()));
}
// Returns the next argument index.
FMT_CONSTEXPR
unsigned
next_arg_id
();
FMT_CONSTEXPR
bool
check_arg_id
(
unsigned
)
{
if
(
next_arg_id_
>
0
)
{
on_error
(
"cannot switch from automatic to manual argument indexing"
);
return
false
;
}
next_arg_id_
=
-
1
;
return
true
;
}
void
check_arg_id
(
basic_string_view
<
Char
>
)
{}
FMT_CONSTEXPR
void
on_error
(
const
char
*
message
)
{
ErrorHandler
::
on_error
(
message
);
}
FMT_CONSTEXPR
ErrorHandler
error_handler
()
const
{
return
*
this
;
}
};
typedef
basic_parse_context
<
char
>
format_parse_context
;
typedef
basic_parse_context
<
wchar_t
>
wformat_parse_context
;
// DEPRECATED!
typedef
basic_parse_context
<
char
>
parse_context
;
typedef
basic_parse_context
<
wchar_t
>
wparse_context
;
namespace
internal
{
// A map from argument names to their values for named arguments.
template
<
typename
Context
>
class
arg_map
{
template
<
typename
Context
>
class
arg_map
{
private:
arg_map
(
const
arg_map
&
)
=
delete
;
void
operator
=
(
const
arg_map
&
)
=
delete
;
arg_map
(
const
arg_map
&
)
=
delete
;
void
operator
=
(
const
arg_map
&
)
=
delete
;
typedef
typename
Context
::
char_type
char_type
;
using
char_type
=
typename
Context
::
char_type
;
struct
entry
{
basic_string_view
<
char_type
>
name
;
basic_format_arg
<
Context
>
arg
;
};
entry
*
map_
;
entry
*
map_
;
unsigned
size_
;
void
push_back
(
value
<
Context
>
val
)
{
const
internal
::
named_arg_base
<
char_type
>
&
named
=
val
.
as_named_arg
()
;
map_
[
size_
]
=
entry
{
named
.
name
,
named
.
template
deserialize
<
Context
>()};
const
auto
&
named
=
*
val
.
named_arg
;
map_
[
size_
]
=
{
named
.
name
,
named
.
template
deserialize
<
Context
>()};
++
size_
;
}
public:
arg_map
()
:
map_
(
FMT_NULL
),
size_
(
0
)
{}
void
init
(
const
basic_format_args
<
Context
>
&
args
);
~
arg_map
()
{
delete
[]
map_
;
}
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
;
if
(
it
->
name
==
name
)
return
it
->
arg
;
}
return
{};
}
...
...
@@ -971,163 +984,97 @@ class arg_map {
// A type-erased reference to an std::locale to avoid heavy <locale> include.
class
locale_ref
{
private:
const
void
*
locale_
;
// A type-erased pointer to std::locale.
friend
class
locale
;
public:
locale_ref
()
:
locale_
(
FMT_NULL
)
{}
template
<
typename
Locale
>
explicit
locale_ref
(
const
Locale
&
loc
);
template
<
typename
Locale
>
Locale
get
()
const
;
};
template
<
typename
OutputIt
,
typename
Context
,
typename
Char
>
class
context_base
{
public:
typedef
OutputIt
iterator
;
private:
basic_parse_context
<
Char
>
parse_context_
;
iterator
out_
;
basic_format_args
<
Context
>
args_
;
locale_ref
loc_
;
protected:
typedef
Char
char_type
;
typedef
basic_format_arg
<
Context
>
format_arg
;
context_base
(
OutputIt
out
,
basic_string_view
<
char_type
>
format_str
,
basic_format_args
<
Context
>
ctx_args
,
locale_ref
loc
=
locale_ref
())
:
parse_context_
(
format_str
),
out_
(
out
),
args_
(
ctx_args
),
loc_
(
loc
)
{}
// Returns the argument with specified index.
format_arg
do_get_arg
(
unsigned
arg_id
)
{
format_arg
arg
=
args_
.
get
(
arg_id
);
if
(
!
arg
)
parse_context_
.
on_error
(
"argument index out of range"
);
return
arg
;
}
// Checks if manual indexing is used and returns the argument with
// specified index.
format_arg
get_arg
(
unsigned
arg_id
)
{
return
this
->
parse_context
().
check_arg_id
(
arg_id
)
?
this
->
do_get_arg
(
arg_id
)
:
format_arg
();
}
const
void
*
locale_
;
// A type-erased pointer to std::locale.
public:
basic_parse_context
<
char_type
>
&
parse_context
()
{
return
parse_context_
;
}
basic_format_args
<
Context
>
args
()
const
{
return
args_
;
}
// DEPRECATED!
basic_format_arg
<
Context
>
arg
(
unsigned
id
)
const
{
return
args_
.
get
(
id
);
}
internal
::
error_handler
error_handler
()
{
return
parse_context_
.
error_handler
();
}
locale_ref
()
:
locale_
(
nullptr
)
{}
template
<
typename
Locale
>
explicit
locale_ref
(
const
Locale
&
loc
);
void
on_error
(
const
char
*
message
)
{
parse_context_
.
on_error
(
message
);
}
// Returns an iterator to the beginning of the output range.
iterator
out
()
{
return
out_
;
}
iterator
begin
()
{
return
out_
;
}
// deprecated
// Advances the begin iterator to ``it``.
void
advance_to
(
iterator
it
)
{
out_
=
it
;
}
locale_ref
locale
()
{
return
loc_
;
}
template
<
typename
Locale
>
Locale
get
()
const
;
};
template
<
typename
Context
,
typename
T
>
struct
get_type
{
typedef
decltype
(
make_value
<
Context
>
(
declval
<
typename
std
::
decay
<
T
>::
type
&>
()))
value_type
;
static
const
type
value
=
value_type
::
type_tag
;
};
template
<
typename
Context
>
FMT_CONSTEXPR11
unsigned
long
long
get_types
()
{
return
0
;
}
template
<
typename
>
constexpr
unsigned
long
long
encode_types
()
{
return
0
;
}
template
<
typename
Context
,
typename
Arg
,
typename
...
Args
>
FMT_CONSTEXPR11
unsigned
long
long
get_types
()
{
return
get_type
<
Context
,
Arg
>::
value
|
(
get_types
<
Context
,
Args
...
>
()
<<
4
);
constexpr
unsigned
long
long
encode_types
()
{
return
mapped_type_constant
<
Arg
,
Context
>::
value
|
(
encode_types
<
Context
,
Args
...
>
()
<<
4
);
}
template
<
typename
Context
,
typename
T
>
FMT_CONSTEXPR
basic_format_arg
<
Context
>
make_arg
(
const
T
&
value
)
{
FMT_CONSTEXPR
basic_format_arg
<
Context
>
make_arg
(
const
T
&
value
)
{
basic_format_arg
<
Context
>
arg
;
arg
.
type_
=
get_type
<
Context
,
T
>::
value
;
arg
.
value_
=
make_value
<
Context
>
(
value
);
arg
.
type_
=
mapped_type_constant
<
T
,
Context
>::
value
;
arg
.
value_
=
arg_mapper
<
Context
>
().
map
(
value
);
return
arg
;
}
template
<
bool
IS_PACKED
,
typename
Context
,
typename
T
>
inline
typename
std
::
enable_if
<
IS_PACKED
,
value
<
Context
>>::
type
make_arg
(
const
T
&
value
)
{
return
make_value
<
Context
>
(
value
);
template
<
bool
IS_PACKED
,
typename
Context
,
typename
T
,
FMT_ENABLE_IF
(
IS_PACKED
)>
inline
value
<
Context
>
make_arg
(
const
T
&
val
)
{
return
arg_mapper
<
Context
>
().
map
(
val
);
}
template
<
bool
IS_PACKED
,
typename
Context
,
typename
T
>
inline
typename
std
::
enable_if
<!
IS_PACKED
,
basic_format_arg
<
Context
>>::
type
make_arg
(
const
T
&
value
)
{
template
<
bool
IS_PACKED
,
typename
Context
,
typename
T
,
FMT_ENABLE_IF
(
!
IS_PACKED
)>
inline
basic_format_arg
<
Context
>
make_arg
(
const
T
&
value
)
{
return
make_arg
<
Context
>
(
value
);
}
}
// namespace internal
// Formatting context.
template
<
typename
OutputIt
,
typename
Char
>
class
basic_format_context
:
public
internal
::
context_base
<
OutputIt
,
basic_format_context
<
OutputIt
,
Char
>
,
Char
>
{
template
<
typename
OutputIt
,
typename
Char
>
class
basic_format_context
{
public:
/** The character type for the output. */
typedef
Char
char_type
;
// using formatter_type = formatter<T, char_type>;
template
<
typename
T
>
struct
formatter_type
{
typedef
formatter
<
T
,
char_type
>
type
;
};
using
char_type
=
Char
;
private:
OutputIt
out_
;
basic_format_args
<
basic_format_context
>
args_
;
internal
::
arg_map
<
basic_format_context
>
map_
;
internal
::
locale_ref
loc_
;
basic_format_context
(
const
basic_format_context
&
)
=
delete
;
void
operator
=
(
const
basic_format_context
&
)
=
delete
;
typedef
internal
::
context_base
<
OutputIt
,
basic_format_context
,
Char
>
base
;
typedef
typename
base
::
format_arg
format_arg
;
using
base
::
get_arg
;
basic_format_context
(
const
basic_format_context
&
)
=
delete
;
void
operator
=
(
const
basic_format_context
&
)
=
delete
;
public:
using
typename
base
::
iterator
;
using
iterator
=
OutputIt
;
using
format_arg
=
basic_format_arg
<
basic_format_context
>
;
template
<
typename
T
>
using
formatter_type
=
formatter
<
T
,
char_type
>
;
/**
Constructs a ``basic_format_context`` object. References to the arguments are
stored in the object so make sure they have appropriate lifetimes.
*/
basic_format_context
(
OutputIt
out
,
basic_string_view
<
char_type
>
format_str
,
basic_format_context
(
OutputIt
out
,
basic_format_args
<
basic_format_context
>
ctx_args
,
internal
::
locale_ref
loc
=
internal
::
locale_ref
())
:
base
(
out
,
format_str
,
ctx_args
,
loc
)
{}
:
out_
(
out
),
args_
(
ctx_args
),
loc_
(
loc
)
{}
format_arg
next_arg
()
{
return
this
->
do_get_arg
(
this
->
parse_context
().
next_arg_id
());
}
format_arg
get_arg
(
unsigned
arg_id
)
{
return
this
->
do_get_arg
(
arg_id
);
}
format_arg
arg
(
int
id
)
const
{
return
args_
.
get
(
id
);
}
// Checks if manual indexing is used and returns the argument with the
// specified name.
format_arg
get_arg
(
basic_string_view
<
char_type
>
name
);
format_arg
arg
(
basic_string_view
<
char_type
>
name
);
internal
::
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
;
}
internal
::
locale_ref
locale
()
{
return
loc_
;
}
};
template
<
typename
Char
>
struct
buffer_context
{
typedef
basic_format_context
<
std
::
back_insert_iterator
<
internal
::
basic_buffer
<
Char
>>
,
Char
>
type
;
};
typedef
buffer_context
<
char
>::
type
format_context
;
typedef
buffer_context
<
wchar_t
>::
type
wformat_context
;
using
buffer_context
=
basic_format_context
<
std
::
back_insert_iterator
<
internal
::
buffer
<
Char
>>
,
Char
>
;
using
format_context
=
buffer_context
<
char
>
;
using
wformat_context
=
buffer_context
<
wchar_t
>
;
/**
\rst
...
...
@@ -1136,74 +1083,48 @@ typedef buffer_context<wchar_t>::type wformat_context;
such as `~fmt::vformat`.
\endrst
*/
template
<
typename
Context
,
typename
...
Args
>
class
format_arg_store
{
template
<
typename
Context
,
typename
...
Args
>
class
format_arg_store
{
private:
static
const
size_t
NUM_ARGS
=
sizeof
...(
Args
);
// Packed is a macro on MinGW so use IS_PACKED instead.
static
const
bool
IS_PACKED
=
NUM_ARGS
<
internal
::
max_packed_args
;
static
const
size_t
num_args
=
sizeof
...(
Args
);
static
const
bool
is_packed
=
num_args
<
internal
::
max_packed_args
;
typedef
typename
std
::
conditional
<
IS_PACKED
,
internal
::
value
<
Context
>
,
basic_format_arg
<
Context
>>::
type
value_type
;
using
value_type
=
conditional_t
<
is_packed
,
internal
::
value
<
Context
>
,
basic_format_arg
<
Context
>>
;
// If the arguments are not packed, add one more element to mark the end.
static
const
size_t
DATA_SIZE
=
NUM_ARGS
+
(
IS_PACKED
&&
NUM_ARGS
!=
0
?
0
:
1
);
value_type
data_
[
DATA_SIZE
];
value_type
data_
[
num_args
+
(
num_args
==
0
?
1
:
0
)];
friend
class
basic_format_args
<
Context
>
;
static
FMT_CONSTEXPR11
unsigned
long
long
get_types
()
{
return
IS_PACKED
?
internal
::
get_types
<
Context
,
Args
...
>
()
:
internal
::
is_unpacked_bit
|
NUM_ARGS
;
}
public:
#if FMT_USE_CONSTEXPR11
static
FMT_CONSTEXPR11
unsigned
long
long
TYPES
=
get_types
();
#else
static
const
unsigned
long
long
TYPES
;
#endif
static
constexpr
unsigned
long
long
types
=
is_packed
?
internal
::
encode_types
<
Context
,
Args
...
>
()
:
internal
::
is_unpacked_bit
|
num_args
;
FMT_DEPRECATED
static
constexpr
unsigned
long
long
TYPES
=
types
;
#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \
(FMT_MSC_VER && FMT_MSC_VER <= 1800)
// Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.
format_arg_store
(
const
Args
&
...
args
)
{
value_type
init
[
DATA_SIZE
]
=
{
internal
::
make_arg
<
IS_PACKED
,
Context
>
(
args
)...};
std
::
memcpy
(
data_
,
init
,
sizeof
(
init
));
}
#else
format_arg_store
(
const
Args
&
...
args
)
:
data_
{
internal
::
make_arg
<
IS_PACKED
,
Context
>
(
args
)...}
{}
#endif
format_arg_store
(
const
Args
&
...
args
)
:
data_
{
internal
::
make_arg
<
is_packed
,
Context
>
(
args
)...}
{}
};
#if !FMT_USE_CONSTEXPR11
template
<
typename
Context
,
typename
...
Args
>
const
unsigned
long
long
format_arg_store
<
Context
,
Args
...
>::
TYPES
=
get_types
();
#endif
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::format_args`. `Context`
can be omitted in which case it defaults to `~fmt::context`.
See `~fmt::arg` for lifetime considerations.
\endrst
*/
template
<
typename
Context
=
format_context
,
typename
...
Args
>
inline
format_arg_store
<
Context
,
Args
...
>
make_format_args
(
const
Args
&
...
args
)
{
return
{
args
...};
}
template
<
typename
Context
=
format_context
,
typename
...
Args
>
inline
format_arg_store
<
Context
,
Args
...
>
make_format_args
(
const
Args
&
...
args
)
{
return
{
args
...};
}
/** Formatting arguments. */
template
<
typename
Context
>
class
basic_format_args
{
template
<
typename
Context
>
class
basic_format_args
{
public:
typedef
unsigned
size_type
;
typedef
basic_format_arg
<
Context
>
format_arg
;
using
size_type
=
int
;
using
format_arg
=
basic_format_arg
<
Context
>
;
private:
// To reduce compiled code size per formatting function call, types of first
...
...
@@ -1215,37 +1136,33 @@ class basic_format_args {
// This is done to reduce compiled code size as 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
internal
::
value
<
Context
>
*
values_
;
const
format_arg
*
args_
;
const
internal
::
value
<
Context
>
*
values_
;
const
format_arg
*
args_
;
};
bool
is_packed
()
const
{
return
(
types_
&
internal
::
is_unpacked_bit
)
==
0
;
}
typename
internal
::
type
type
(
unsigned
index
)
const
{
unsigned
shift
=
index
*
4
;
return
static_cast
<
typename
internal
::
type
>
(
(
types_
&
(
0xfull
<<
shift
))
>>
shift
);
internal
::
type
type
(
int
index
)
const
{
int
shift
=
index
*
4
;
return
static_cast
<
internal
::
type
>
((
types_
&
(
0xfull
<<
shift
))
>>
shift
);
}
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
;
}
void
set_data
(
const
internal
::
value
<
Context
>
*
values
)
{
values_
=
values
;
}
void
set_data
(
const
format_arg
*
args
)
{
args_
=
args
;
}
format_arg
do_get
(
size_type
index
)
const
{
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
];
if
(
index
<
num_args
)
arg
=
args_
[
index
];
return
arg
;
}
if
(
index
>
internal
::
max_packed_args
)
return
arg
;
if
(
index
>
internal
::
max_packed_args
)
return
arg
;
arg
.
type_
=
type
(
index
);
if
(
arg
.
type_
==
internal
::
none_type
)
return
arg
;
internal
::
value
<
Context
>
&
val
=
arg
.
value_
;
if
(
arg
.
type_
==
internal
::
none_type
)
return
arg
;
internal
::
value
<
Context
>&
val
=
arg
.
value_
;
val
=
values_
[
index
];
return
arg
;
}
...
...
@@ -1259,8 +1176,8 @@ class basic_format_args {
\endrst
*/
template
<
typename
...
Args
>
basic_format_args
(
const
format_arg_store
<
Context
,
Args
...
>
&
store
)
:
types_
(
static_cast
<
unsigned
long
long
>
(
store
.
TYPES
))
{
basic_format_args
(
const
format_arg_store
<
Context
,
Args
...
>
&
store
)
:
types_
(
static_cast
<
unsigned
long
long
>
(
store
.
types
))
{
set_data
(
store
.
data_
);
}
...
...
@@ -1269,131 +1186,133 @@ class basic_format_args {
Constructs a `basic_format_args` object from a dynamic set of arguments.
\endrst
*/
basic_format_args
(
const
format_arg
*
args
,
size_type
count
)
:
types_
(
internal
::
is_unpacked_bit
|
count
)
{
basic_format_args
(
const
format_arg
*
args
,
int
count
)
:
types_
(
internal
::
is_unpacked_bit
|
internal
::
to_unsigned
(
count
)
)
{
set_data
(
args
);
}
/** Returns the argument at specified index. */
format_arg
get
(
size_type
index
)
const
{
format_arg
get
(
int
index
)
const
{
format_arg
arg
=
do_get
(
index
);
if
(
arg
.
type_
==
internal
::
named_arg_type
)
arg
=
arg
.
value_
.
as_named_arg
().
template
deserialize
<
Context
>();
arg
=
arg
.
value_
.
named_arg
->
template
deserialize
<
Context
>();
return
arg
;
}
size_type
max_size
()
const
{
int
max_size
()
const
{
unsigned
long
long
max_packed
=
internal
::
max_packed_args
;
return
static_cast
<
size_type
>
(
is_packed
()
?
max_packed
:
types_
&
~
internal
::
is_unpacked_bit
);
return
static_cast
<
int
>
(
is_packed
()
?
max_packed
:
types_
&
~
internal
::
is_unpacked_bit
);
}
};
/** An alias to ``basic_format_args<context>``. */
// It is a separate type rather than a
typedef
to make symbols readable.
// It is a separate type rather than a
n alias
to make symbols readable.
struct
format_args
:
basic_format_args
<
format_context
>
{
template
<
typename
...
Args
>
format_args
(
Args
&&
...
arg
)
:
basic_format_args
<
format_context
>
(
std
::
forward
<
Args
>
(
arg
)...)
{}
template
<
typename
...
Args
>
format_args
(
Args
&&
...
args
)
:
basic_format_args
<
format_context
>
(
std
::
forward
<
Args
>
(
args
)...)
{}
};
struct
wformat_args
:
basic_format_args
<
wformat_context
>
{
template
<
typename
...
Args
>
wformat_args
(
Args
&&
...
arg
)
:
basic_format_args
<
wformat_context
>
(
std
::
forward
<
Args
>
(
arg
)...)
{}
template
<
typename
...
Args
>
wformat_args
(
Args
&&
...
args
)
:
basic_format_args
<
wformat_context
>
(
std
::
forward
<
Args
>
(
args
)...)
{}
};
#define FMT_ENABLE_IF_T(B, T) typename std::enable_if<B, T>::type
template
<
typename
Container
>
struct
is_contiguous
:
std
::
false_type
{};
#ifndef FMT_USE_ALIAS_TEMPLATES
# define FMT_USE_ALIAS_TEMPLATES FMT_HAS_FEATURE(cxx_alias_templates)
#endif
#if FMT_USE_ALIAS_TEMPLATES
/** String's character type. */
template
<
typename
S
>
using
char_t
=
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
typename
internal
::
char_t
<
S
>::
type
);
#define FMT_CHAR(S) fmt::char_t<S>
#else
template
<
typename
S
>
struct
char_t
:
std
::
enable_if
<
internal
::
is_string
<
S
>::
value
,
typename
internal
::
char_t
<
S
>::
type
>
{};
#define FMT_CHAR(S) typename char_t<S>::type
#endif
template
<
typename
Char
>
struct
is_contiguous
<
std
::
basic_string
<
Char
>>
:
std
::
true_type
{};
namespace
internal
{
template
<
typename
Char
>
struct
named_arg_base
{
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
<
typename
buffer_context
<
Char
>::
type
>
)];
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
{
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
;
}
};
template
<
typename
T
,
typename
Char
>
struct
named_arg
:
named_arg_base
<
Char
>
{
const
T
&
value
;
template
<
typename
T
,
typename
Char
>
struct
named_arg
:
named_arg_base
<
Char
>
{
const
T
&
value
;
named_arg
(
basic_string_view
<
Char
>
name
,
const
T
&
val
)
named_arg
(
basic_string_view
<
Char
>
name
,
const
T
&
val
)
:
named_arg_base
<
Char
>
(
name
),
value
(
val
)
{}
};
template
<
typename
...
Args
,
typename
S
>
inline
typename
std
::
enable_if
<!
is_compile_string
<
S
>::
value
>::
type
check_format_string
(
const
S
&
)
{}
template
<
typename
...
Args
,
typename
S
>
typename
std
::
enable_if
<
is_compile_string
<
S
>::
value
>::
type
check_format_string
(
S
);
template
<
typename
S
,
typename
...
Args
>
struct
checked_args
:
format_arg_store
<
typename
buffer_context
<
FMT_CHAR
(
S
)
>::
type
,
Args
...
>
{
typedef
typename
buffer_context
<
FMT_CHAR
(
S
)
>::
type
context
;
checked_args
(
const
S
&
format_str
,
const
Args
&
...
args
)
:
format_arg_store
<
context
,
Args
...
>
(
args
...)
{
internal
::
check_format_string
<
Args
...
>
(
format_str
);
}
basic_format_args
<
context
>
operator
*
()
const
{
return
*
this
;
}
};
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)
static_assert
(
is_compile_string
<
S
>::
value
,
"FMT_ENFORCE_COMPILE_STRING requires all format strings to "
"utilize FMT_STRING() or fmt()."
);
#endif
}
template
<
typename
...
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
void
check_format_string
(
S
);
struct
view
{};
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
>>
()
||
!
std
::
is_reference
<
Args
>
())...
>::
value
,
"passing views as lvalues is disallowed"
);
check_format_string
<
remove_const_t
<
remove_reference_t
<
Args
>>
...
>
(
format_str
);
return
{
args
...};
}
template
<
typename
Char
>
std
::
basic_string
<
Char
>
vformat
(
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
);
std
::
basic_string
<
Char
>
vformat
(
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
Char
>>
args
);
template
<
typename
Char
>
typename
buffer_context
<
Char
>::
type
::
iterator
vformat_to
(
internal
::
basic_buffer
<
Char
>
&
buf
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
);
}
typename
buffer_context
<
Char
>::
iterator
vformat_to
(
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
Char
>
>
args
);
}
// namespace internal
/**
\rst
Returns a named argument to be used in a formatting function.
The named argument holds a reference and does not extend the lifetime
of its arguments.
Consequently, a dangling reference can accidentally be created.
The user should take care to only pass this function temporaries when
the named argument is itself a temporary, as per the following example.
**Example**::
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
\endrst
*/
template
<
typename
T
>
inline
internal
::
named_arg
<
T
,
char
>
arg
(
string_view
name
,
const
T
&
arg
)
{
return
{
name
,
arg
};
}
template
<
typename
T
>
inline
internal
::
named_arg
<
T
,
wchar_t
>
arg
(
wstring_view
name
,
const
T
&
arg
)
{
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
};
}
...
...
@@ -1401,42 +1320,34 @@ inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {
template
<
typename
S
,
typename
T
,
typename
Char
>
void
arg
(
S
,
internal
::
named_arg
<
T
,
Char
>
)
=
delete
;
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
::
basic_buffer
<
Char
>
>:
std
::
true_type
{};
/** Formats a string and writes the output to ``out``. */
template
<
typename
Container
,
typename
S
>
typename
std
::
enable_if
<
is_contiguous
<
Container
>::
value
,
std
::
back_insert_iterator
<
Container
>>::
type
vformat_to
(
std
::
back_insert_iterator
<
Container
>
out
,
const
S
&
format_str
,
basic_format_args
<
typename
buffer_context
<
FMT_CHAR
(
S
)
>::
type
>
args
)
{
internal
::
container_buffer
<
Container
>
buf
(
internal
::
get_container
(
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
(
internal
::
is_contiguous_back_insert_iterator
<
OutputIt
>::
value
)
>
OutputIt
vformat_to
(
OutputIt
out
,
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
Char
>>
args
)
{
using
container
=
remove_reference_t
<
decltype
(
internal
::
get_container
(
out
))
>
;
internal
::
container_buffer
<
container
>
buf
((
internal
::
get_container
(
out
)));
internal
::
vformat_to
(
buf
,
to_string_view
(
format_str
),
args
);
return
out
;
}
template
<
typename
Container
,
typename
S
,
typename
...
Args
>
inline
typename
std
::
enable_if
<
is_contiguous
<
Container
>::
value
&&
internal
::
is_string
<
S
>::
value
,
std
::
back_insert_iterator
<
Container
>>::
type
format_to
(
std
::
back_insert_iterator
<
Container
>
out
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
internal
::
checked_args
<
S
,
Args
...
>
ca
(
format_str
,
args
...);
return
vformat_to
(
out
,
to_string_view
(
format_str
),
*
ca
);
template
<
typename
Container
,
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
is_contiguous
<
Container
>
::
value
&&
internal
::
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
),
{
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...)});
}
template
<
typename
S
,
typename
Char
=
FMT_CHAR
(
S
)
>
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
vformat
(
const
S
&
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
Char
>>
args
)
{
return
internal
::
vformat
(
to_string_view
(
format_str
),
args
);
}
...
...
@@ -1450,16 +1361,17 @@ inline std::basic_string<Char> vformat(
std::string message = fmt::format("The answer is {}", 42);
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
std
::
basic_string
<
FMT_CHAR
(
S
)
>
format
(
const
S
&
format_str
,
const
Args
&
...
args
)
{
// 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
::
checked_args
<
S
,
Args
...
>
(
format_str
,
args
...)
);
{
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...)}
);
}
FMT_API
void
vprint
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
);
FMT_API
void
vprint
(
std
::
FILE
*
f
,
wstring_view
format_str
,
wformat_args
args
);
FMT_API
void
vprint
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
);
FMT_API
void
vprint
(
std
::
FILE
*
f
,
wstring_view
format_str
,
wformat_args
args
);
/**
\rst
...
...
@@ -1472,11 +1384,11 @@ FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args);
fmt::print(stderr, "Don't {}!", "panic");
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
void
)
print
(
std
::
FILE
*
f
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_string
<
S
>
::
value
)
>
inline
void
print
(
std
::
FILE
*
f
,
const
S
&
format_str
,
Args
&
&
...
args
)
{
vprint
(
f
,
to_string_view
(
format_str
),
internal
::
checked_args
<
S
,
Args
...
>
(
format_str
,
args
...));
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
}
FMT_API
void
vprint
(
string_view
format_str
,
format_args
args
);
...
...
@@ -1491,11 +1403,11 @@ FMT_API void vprint(wstring_view format_str, wformat_args args);
fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
void
)
print
(
const
S
&
format_str
,
const
Args
&
...
args
)
{
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_string
<
S
>
::
value
)
>
inline
void
print
(
const
S
&
format_str
,
Args
&
&
...
args
)
{
vprint
(
to_string_view
(
format_str
),
internal
::
checked_args
<
S
,
Args
...
>
(
format_str
,
args
...));
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...));
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/format-inl.h
View file @
e149433a
...
...
@@ -19,6 +19,7 @@
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#include <cstring> // for std::memmove
#include <cwchar>
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
# include <locale>
#endif
...
...
@@ -46,30 +47,29 @@
#ifdef _MSC_VER
# pragma warning(push)
#
pragma warning(disable
: 4127) // conditional expression is constant
#
pragma warning(disable
: 4702) // unreachable code
#
pragma warning(disable
: 4127) // conditional expression is constant
#
pragma warning(disable
: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
#
pragma warning(disable
: 4996)
#
pragma warning(disable
: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
inline
fmt
::
internal
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
inline
fmt
::
internal
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
return
fmt
::
internal
::
null
<>
();
}
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
fmt
::
internal
::
null
<>
();
}
FMT_BEGIN_NAMESPACE
namespace
{
namespace
internal
{
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline
int
fmt_snprintf
(
char
*
buffer
,
size_t
size
,
const
char
*
format
,
...)
{
inline
int
fmt_snprintf
(
char
*
buffer
,
size_t
size
,
const
char
*
format
,
...)
{
va_list
args
;
va_start
(
args
,
format
);
int
result
=
vsnprintf_s
(
buffer
,
size
,
_TRUNCATE
,
format
,
args
);
...
...
@@ -79,13 +79,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
typedef
void
(
*
FormatFunc
)(
internal
::
buffer
&
,
int
,
string_view
);
using
format_func
=
void
(
*
)(
internal
::
buffer
<
char
>&
,
int
,
string_view
);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
...
...
@@ -96,18 +90,18 @@ typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int
safe_strerror
(
int
error_code
,
char
*&
buffer
,
std
::
size_t
buffer_size
)
FMT_NOEXCEPT
{
FMT_ASSERT
(
buffer
!=
FMT_NULL
&&
buffer_size
!=
0
,
"invalid buffer"
);
FMT_FUNC
int
safe_strerror
(
int
error_code
,
char
*&
buffer
,
std
::
size_t
buffer_size
)
FMT_NOEXCEPT
{
FMT_ASSERT
(
buffer
!=
nullptr
&&
buffer_size
!=
0
,
"invalid buffer"
);
class
dispatcher
{
private:
int
error_code_
;
char
*&
buffer_
;
char
*&
buffer_
;
std
::
size_t
buffer_size_
;
// A noop assignment operator to avoid bogus warnings.
void
operator
=
(
const
dispatcher
&
)
{}
void
operator
=
(
const
dispatcher
&
)
{}
// Handle the result of XSI-compliant version of strerror_r.
int
handle
(
int
result
)
{
...
...
@@ -116,7 +110,7 @@ int safe_strerror(
}
// Handle the result of GNU-specific version of strerror_r.
int
handle
(
char
*
message
)
{
int
handle
(
char
*
message
)
{
// If the buffer is full then the message is probably truncated.
if
(
message
==
buffer_
&&
strlen
(
buffer_
)
==
buffer_size_
-
1
)
return
ERANGE
;
...
...
@@ -132,8 +126,8 @@ int safe_strerror(
// Fallback to strerror_s when strerror_r is not available.
int
fallback
(
int
result
)
{
// If the buffer is full then the message is probably truncated.
return
result
==
0
&&
strlen
(
buffer_
)
==
buffer_size_
-
1
?
ERANGE
:
result
;
return
result
==
0
&&
strlen
(
buffer_
)
==
buffer_size_
-
1
?
ERANGE
:
result
;
}
#if !FMT_MSC_VER
...
...
@@ -146,17 +140,15 @@ int safe_strerror(
#endif
public:
dispatcher
(
int
err_code
,
char
*&
buf
,
std
::
size_t
buf_size
)
dispatcher
(
int
err_code
,
char
*&
buf
,
std
::
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_
));
}
int
run
()
{
return
handle
(
strerror_r
(
error_code_
,
buffer_
,
buffer_size_
));
}
};
return
dispatcher
(
error_code
,
buffer
,
buffer_size
).
run
();
}
void
format_error_code
(
internal
::
buffer
&
out
,
int
error_code
,
FMT_FUNC
void
format_error_code
(
internal
::
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
...
...
@@ -166,14 +158,13 @@ void format_error_code(internal::buffer &out, int error_code,
static
const
char
ERROR_STR
[]
=
"error "
;
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std
::
size_t
error_code_size
=
sizeof
(
SEP
)
+
sizeof
(
ERROR_STR
)
-
2
;
typedef
internal
::
int_traits
<
int
>::
main_type
main_type
;
main_type
abs_value
=
static_cast
<
main_type
>
(
error_code
);
auto
abs_value
=
static_cast
<
uint32_or_64_t
<
int
>>
(
error_code
);
if
(
internal
::
is_negative
(
error_code
))
{
abs_value
=
0
-
abs_value
;
++
error_code_size
;
}
error_code_size
+=
internal
::
to_unsigned
(
internal
::
count_digits
(
abs_value
));
writer
w
(
out
);
internal
::
writer
w
(
out
);
if
(
message
.
size
()
<=
inline_buffer_size
-
error_code_size
)
{
w
.
write
(
message
);
w
.
write
(
SEP
);
...
...
@@ -183,122 +174,128 @@ void format_error_code(internal::buffer &out, int error_code,
assert
(
out
.
size
()
<=
inline_buffer_size
);
}
void
report_error
(
FormatFunc
func
,
int
error_code
,
// A wrapper around fwrite that throws on error.
FMT_FUNC
void
fwrite_fully
(
const
void
*
ptr
,
size_t
size
,
size_t
count
,
FILE
*
stream
)
{
size_t
written
=
std
::
fwrite
(
ptr
,
size
,
count
,
stream
);
if
(
written
<
count
)
{
FMT_THROW
(
system_error
(
errno
,
"cannot write to file"
));
}
}
FMT_FUNC
void
report_error
(
format_func
func
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
memory_buffer
full_message
;
func
(
full_message
,
error_code
,
message
);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std
::
fwrite
(
full_message
.
data
(),
full_message
.
size
(),
1
,
stderr
);
// Don't use fwrite_fully because the latter may throw.
(
void
)
std
::
fwrite
(
full_message
.
data
(),
full_message
.
size
(),
1
,
stderr
);
std
::
fputc
(
'\n'
,
stderr
);
}
}
// namespace
FMT_FUNC
size_t
internal
::
count_code_points
(
basic_string_view
<
char8_t
>
s
)
{
const
char8_t
*
data
=
s
.
data
();
size_t
num_code_points
=
0
;
for
(
size_t
i
=
0
,
size
=
s
.
size
();
i
!=
size
;
++
i
)
{
if
((
data
[
i
]
&
0xc0
)
!=
0x80
)
++
num_code_points
;
}
return
num_code_points
;
}
}
// namespace internal
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace
internal
{
template
<
typename
Locale
>
locale_ref
::
locale_ref
(
const
Locale
&
loc
)
:
locale_
(
&
loc
)
{
locale_ref
::
locale_ref
(
const
Locale
&
loc
)
:
locale_
(
&
loc
)
{
static_assert
(
std
::
is_same
<
Locale
,
std
::
locale
>::
value
,
""
);
}
template
<
typename
Locale
>
Locale
locale_ref
::
get
()
const
{
template
<
typename
Locale
>
Locale
locale_ref
::
get
()
const
{
static_assert
(
std
::
is_same
<
Locale
,
std
::
locale
>::
value
,
""
);
return
locale_
?
*
static_cast
<
const
std
::
locale
*>
(
locale_
)
:
std
::
locale
();
}
template
<
typename
Char
>
FMT_FUNC
Char
thousands_sep_impl
(
locale_ref
loc
)
{
return
std
::
use_facet
<
std
::
numpunct
<
Char
>
>
(
loc
.
get
<
std
::
locale
>
()).
thousands_sep
();
template
<
typename
Char
>
FMT_FUNC
Char
thousands_sep_impl
(
locale_ref
loc
)
{
return
std
::
use_facet
<
std
::
numpunct
<
Char
>>
(
loc
.
get
<
std
::
locale
>
())
.
thousands_sep
();
}
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 internal
#else
template
<
typename
Char
>
FMT_FUNC
Char
internal
::
thousands_sep_impl
(
locale_ref
)
{
return
FMT_STATIC_THOUSANDS_SEPARATOR
;
}
template
<
typename
Char
>
FMT_FUNC
Char
internal
::
decimal_point_impl
(
locale_ref
)
{
return
'.'
;
}
#endif
FMT_FUNC
void
system_error
::
init
(
int
err_code
,
string_view
format_str
,
format_args
args
)
{
FMT_API
FMT_FUNC
format_error
::~
format_error
()
FMT_NOEXCEPT
{}
FMT_API
FMT_FUNC
system_error
::~
system_error
()
FMT_NOEXCEPT
{}
FMT_FUNC
void
system_error
::
init
(
int
err_code
,
string_view
format_str
,
format_args
args
)
{
error_code_
=
err_code
;
memory_buffer
buffer
;
format_system_error
(
buffer
,
err_code
,
vformat
(
format_str
,
args
));
std
::
runtime_error
&
base
=
*
this
;
std
::
runtime_error
&
base
=
*
this
;
base
=
std
::
runtime_error
(
to_string
(
buffer
));
}
namespace
internal
{
template
<
typename
T
>
int
char_traits
<
char
>::
format_float
(
char
*
buf
,
std
::
size_t
size
,
const
char
*
format
,
int
precision
,
T
value
)
{
return
precision
<
0
?
FMT_SNPRINTF
(
buf
,
size
,
format
,
value
)
:
FMT_SNPRINTF
(
buf
,
size
,
format
,
precision
,
value
);
template
<
>
FMT_FUNC
int
count_digits
<
4
>
(
internal
::
fallback_uintptr
n
)
{
// Assume little endian; pointer formatting is implementation-defined anyway.
int
i
=
static_cast
<
int
>
(
sizeof
(
void
*
))
-
1
;
while
(
i
>
0
&&
n
.
value
[
i
]
==
0
)
--
i
;
auto
char_digits
=
std
::
numeric_limits
<
unsigned
char
>::
digits
/
4
;
return
i
>=
0
?
i
*
char_digits
+
count_digits
<
4
,
unsigned
>
(
n
.
value
[
i
])
:
1
;
}
template
<
typename
T
>
int
char_traits
<
wchar_t
>::
format_float
(
wchar_t
*
buf
,
std
::
size_t
size
,
const
wchar_t
*
format
,
int
precision
,
int
format_float
(
char
*
buf
,
std
::
size_t
size
,
const
char
*
format
,
int
precision
,
T
value
)
{
return
precision
<
0
?
FMT_SWPRINTF
(
buf
,
size
,
format
,
value
)
:
FMT_SWPRINTF
(
buf
,
size
,
format
,
precision
,
value
);
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if
(
precision
>
100000
)
throw
std
::
runtime_error
(
"fuzz mode - avoid large allocation inside snprintf"
);
#endif
// Suppress the warning about nonliteral format string.
auto
snprintf_ptr
=
FMT_SNPRINTF
;
return
precision
<
0
?
snprintf_ptr
(
buf
,
size
,
format
,
value
)
:
snprintf_ptr
(
buf
,
size
,
format
,
precision
,
value
);
}
template
<
typename
T
>
const
char
basic_data
<
T
>::
DIGITS
[]
=
const
char
basic_data
<
T
>::
digits
[]
=
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899"
;
template
<
typename
T
>
const
char
basic_data
<
T
>::
hex_digits
[]
=
"0123456789abcdef"
;
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
factor * 100, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, \
factor * 1000000, factor * 10000000, factor * 100000000, \
factor * 1000000000
template
<
typename
T
>
const
uint
32_t
basic_data
<
T
>::
POWERS_OF_10_32
[]
=
{
1
,
FMT_POWERS_OF_10
(
1
)
};
const
uint
64_t
basic_data
<
T
>::
powers_of_10_64
[]
=
{
1
,
FMT_POWERS_OF_10
(
1
),
FMT_POWERS_OF_10
(
1000000000ull
),
10000000000000000000ull
};
template
<
typename
T
>
const
uint32_t
basic_data
<
T
>::
ZERO_OR_POWERS_OF_10_32
[]
=
{
0
,
FMT_POWERS_OF_10
(
1
)
};
const
uint32_t
basic_data
<
T
>::
zero_or_powers_of_10_32
[]
=
{
0
,
FMT_POWERS_OF_10
(
1
)};
template
<
typename
T
>
const
uint64_t
basic_data
<
T
>::
ZERO_OR_POWERS_OF_10_64
[]
=
{
0
,
FMT_POWERS_OF_10
(
1
),
FMT_POWERS_OF_10
(
1000000000ull
),
10000000000000000000ull
};
const
uint64_t
basic_data
<
T
>::
zero_or_powers_of_10_64
[]
=
{
0
,
FMT_POWERS_OF_10
(
1
),
FMT_POWERS_OF_10
(
1000000000ull
),
10000000000000000000ull
};
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
// These are generated by support/compute-powers.py.
template
<
typename
T
>
const
uint64_t
basic_data
<
T
>::
POW10_SIGNIFICANDS
[]
=
{
const
uint64_t
basic_data
<
T
>::
pow10_significands
[]
=
{
0xfa8fd5a0081c0288
,
0xbaaee17fa23ebf76
,
0x8b16fb203055ac76
,
0xcf42894a5dce35ea
,
0x9a6bb0aa55653b2d
,
0xe61acf033d1a45df
,
0xab70fe17c79ac6ca
,
0xff77b1fcbebcdc4f
,
0xbe5691ef416bd60c
,
...
...
@@ -333,7 +330,7 @@ const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
// to significands above.
template
<
typename
T
>
const
int16_t
basic_data
<
T
>::
POW10_EXPONENTS
[]
=
{
const
int16_t
basic_data
<
T
>::
pow10_exponents
[]
=
{
-
1220
,
-
1193
,
-
1166
,
-
1140
,
-
1113
,
-
1087
,
-
1060
,
-
1034
,
-
1007
,
-
980
,
-
954
,
-
927
,
-
901
,
-
874
,
-
847
,
-
821
,
-
794
,
-
768
,
-
741
,
-
715
,
-
688
,
-
661
,
-
635
,
-
608
,
-
582
,
-
555
,
-
529
,
-
502
,
-
475
,
-
449
,
-
422
,
-
396
,
-
369
,
...
...
@@ -341,22 +338,26 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {
-
50
,
-
24
,
3
,
30
,
56
,
83
,
109
,
136
,
162
,
189
,
216
,
242
,
269
,
295
,
322
,
348
,
375
,
402
,
428
,
455
,
481
,
508
,
534
,
561
,
588
,
614
,
641
,
667
,
694
,
720
,
747
,
774
,
800
,
827
,
853
,
880
,
907
,
933
,
960
,
986
,
1013
,
1039
,
1066
};
827
,
853
,
880
,
907
,
933
,
960
,
986
,
1013
,
1039
,
1066
};
template
<
typename
T
>
const
char
basic_data
<
T
>::
foreground_color
[]
=
"
\x1b
[38;2;"
;
template
<
typename
T
>
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
>::
FOREGROUND_COLOR
[]
=
"
\x1b
[38;2;"
;
template
<
typename
T
>
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
>
struct
bits
{
static
FMT_CONSTEXPR_DECL
const
int
value
=
static_cast
<
int
>
(
sizeof
(
T
)
*
std
::
numeric_limits
<
unsigned
char
>::
digits
)
;
}
;
// A handmade floating-point number f * pow(2, e).
class
fp
{
private:
typedef
uint64_t
significand_type
;
using
significand_type
=
uint64_t
;
// All sizes are in bits.
static
FMT_CONSTEXPR_DECL
const
int
char_size
=
std
::
numeric_limits
<
unsigned
char
>::
digits
;
// Subtract 1 to account for an implicit most significant bit in the
// normalized form.
static
FMT_CONSTEXPR_DECL
const
int
double_significand_size
=
...
...
@@ -369,20 +370,18 @@ class fp {
int
e
;
static
FMT_CONSTEXPR_DECL
const
int
significand_size
=
sizeof
(
significand_type
)
*
char_siz
e
;
bits
<
significand_type
>::
valu
e
;
fp
()
:
f
(
0
),
e
(
0
)
{}
fp
(
uint64_t
f_val
,
int
e_val
)
:
f
(
f_val
),
e
(
e_val
)
{}
fp
()
:
f
(
0
),
e
(
0
)
{}
fp
(
uint64_t
f_val
,
int
e_val
)
:
f
(
f_val
),
e
(
e_val
)
{}
// Constructs fp from an IEEE754 double. It is a template to prevent compile
// errors on platforms where double is not IEEE754.
template
<
typename
Double
>
explicit
fp
(
Double
d
)
{
template
<
typename
Double
>
explicit
fp
(
Double
d
)
{
// Assume double is in the format [sign][exponent][significand].
typedef
std
::
numeric_limits
<
Double
>
limits
;
const
int
double_size
=
static_cast
<
int
>
(
sizeof
(
Double
)
*
char_size
);
using
limits
=
std
::
numeric_limits
<
Double
>
;
const
int
exponent_size
=
double_siz
e
-
double_significand_size
-
1
;
// -1 for sign
bits
<
Double
>::
valu
e
-
double_significand_size
-
1
;
// -1 for sign
const
uint64_t
significand_mask
=
implicit_bit
-
1
;
const
uint64_t
exponent_mask
=
(
~
0ull
>>
1
)
&
~
significand_mask
;
const
int
exponent_bias
=
(
1
<<
exponent_size
)
-
limits
::
max_exponent
-
1
;
...
...
@@ -397,8 +396,7 @@ class fp {
}
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
template
<
int
SHIFT
=
0
>
void
normalize
()
{
template
<
int
SHIFT
=
0
>
void
normalize
()
{
// Handle subnormals.
auto
shifted_implicit_bit
=
implicit_bit
<<
SHIFT
;
while
((
f
&
shifted_implicit_bit
)
==
0
)
{
...
...
@@ -415,9 +413,9 @@ class fp {
// a boundary is a value half way between the number and its predecessor
// (lower) or successor (upper). The upper boundary is normalized and lower
// has the same exponent but may be not normalized.
void
compute_boundaries
(
fp
&
lower
,
fp
&
upper
)
const
{
lower
=
f
==
implicit_bit
?
fp
((
f
<<
2
)
-
1
,
e
-
2
)
:
fp
((
f
<<
1
)
-
1
,
e
-
1
);
void
compute_boundaries
(
fp
&
lower
,
fp
&
upper
)
const
{
lower
=
f
==
implicit_bit
?
fp
((
f
<<
2
)
-
1
,
e
-
2
)
:
fp
((
f
<<
1
)
-
1
,
e
-
1
);
upper
=
fp
((
f
<<
1
)
+
1
,
e
-
1
);
upper
.
normalize
<
1
>
();
// 1 is to account for the exponent shift above.
lower
.
f
<<=
lower
.
e
-
upper
.
e
;
...
...
@@ -432,14 +430,16 @@ inline fp operator-(fp x, fp y) {
}
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
FMT_API
fp
operator
*
(
fp
x
,
fp
y
);
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
FMT_API
fp
get_cached_power
(
int
min_exponent
,
int
&
pow10_exponent
);
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be
// normalized.
FMT_FUNC
fp
operator
*
(
fp
x
,
fp
y
)
{
int
exp
=
x
.
e
+
y
.
e
+
64
;
#if FMT_USE_INT128
auto
product
=
static_cast
<
__uint128_t
>
(
x
.
f
)
*
y
.
f
;
auto
f
=
static_cast
<
uint64_t
>
(
product
>>
64
);
if
((
static_cast
<
uint64_t
>
(
product
)
&
(
1ULL
<<
63
))
!=
0
)
++
f
;
return
fp
(
f
,
exp
);
#else
// Multiply 32-bit parts of significands.
uint64_t
mask
=
(
1ULL
<<
32
)
-
1
;
uint64_t
a
=
x
.
f
>>
32
,
b
=
x
.
f
&
mask
;
...
...
@@ -447,351 +447,376 @@ FMT_FUNC fp operator*(fp x, fp y) {
uint64_t
ac
=
a
*
c
,
bc
=
b
*
c
,
ad
=
a
*
d
,
bd
=
b
*
d
;
// Compute mid 64-bit of result and round.
uint64_t
mid
=
(
bd
>>
32
)
+
(
ad
&
mask
)
+
(
bc
&
mask
)
+
(
1U
<<
31
);
return
fp
(
ac
+
(
ad
>>
32
)
+
(
bc
>>
32
)
+
(
mid
>>
32
),
x
.
e
+
y
.
e
+
64
);
return
fp
(
ac
+
(
ad
>>
32
)
+
(
bc
>>
32
)
+
(
mid
>>
32
),
exp
);
#endif
}
FMT_FUNC
fp
get_cached_power
(
int
min_exponent
,
int
&
pow10_exponent
)
{
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 28.
FMT_FUNC
fp
get_cached_power
(
int
min_exponent
,
int
&
pow10_exponent
)
{
const
double
one_over_log2_10
=
0.30102999566398114
;
// 1 / log2(10)
int
index
=
static_cast
<
int
>
(
std
::
ceil
(
(
min_exponent
+
fp
::
significand_size
-
1
)
*
one_over_log2_10
));
int
index
=
static_cast
<
int
>
(
std
::
ceil
(
(
min_exponent
+
fp
::
significand_size
-
1
)
*
one_over_log2_10
));
// Decimal exponent of the first (smallest) cached power of 10.
const
int
first_dec_exp
=
-
348
;
// Difference between 2 consecutive decimal exponents in cached powers of 10.
const
int
dec_exp_step
=
8
;
index
=
(
index
-
first_dec_exp
-
1
)
/
dec_exp_step
+
1
;
pow10_exponent
=
first_dec_exp
+
index
*
dec_exp_step
;
return
fp
(
data
::
POW10_SIGNIFICANDS
[
index
],
data
::
POW10_EXPONENTS
[
index
]);
}
FMT_FUNC
bool
grisu2_round
(
char
*
buf
,
int
&
size
,
int
max_digits
,
uint64_t
delta
,
uint64_t
remainder
,
uint64_t
exp
,
uint64_t
diff
,
int
&
exp10
)
{
while
(
remainder
<
diff
&&
delta
-
remainder
>=
exp
&&
(
remainder
+
exp
<
diff
||
diff
-
remainder
>
remainder
+
exp
-
diff
))
{
--
buf
[
size
-
1
];
remainder
+=
exp
;
}
if
(
size
>
max_digits
)
{
--
size
;
++
exp10
;
if
(
buf
[
size
]
>=
'5'
)
return
false
;
}
return
true
;
return
fp
(
data
::
pow10_significands
[
index
],
data
::
pow10_exponents
[
index
]);
}
enum
round_direction
{
unknown
,
up
,
down
};
// Given the divisor (normally a power of 10), the remainder = v % divisor for
// some number v and the error, returns whether v should be rounded up, down, or
// whether the rounding direction can't be determined due to error.
// error should be less than divisor / 2.
inline
round_direction
get_round_direction
(
uint64_t
divisor
,
uint64_t
remainder
,
uint64_t
error
)
{
FMT_ASSERT
(
remainder
<
divisor
,
""
);
// divisor - remainder won't overflow.
FMT_ASSERT
(
error
<
divisor
,
""
);
// divisor - error won't overflow.
FMT_ASSERT
(
error
<
divisor
-
error
,
""
);
// error * 2 won't overflow.
// Round down if (remainder + error) * 2 <= divisor.
if
(
remainder
<=
divisor
-
remainder
&&
error
*
2
<=
divisor
-
remainder
*
2
)
return
down
;
// Round up if (remainder - error) * 2 >= divisor.
if
(
remainder
>=
error
&&
remainder
-
error
>=
divisor
-
(
remainder
-
error
))
{
return
up
;
}
return
unknown
;
}
namespace
digits
{
enum
result
{
more
,
// Generate more digits.
done
,
// Done generating digits.
error
// Digit generation cancelled due to an error.
};
}
// Generates output using Grisu2 digit-gen algorithm.
FMT_FUNC
bool
grisu2_gen_digits
(
char
*
buf
,
int
&
size
,
uint32_t
hi
,
uint64_t
lo
,
int
&
exp
,
uint64_t
delta
,
const
fp
&
one
,
const
fp
&
diff
,
int
max_digits
)
{
// Generate digits for the most significant part (hi).
while
(
exp
>
0
)
{
// Generates output using the Grisu digit-gen algorithm.
// error: the size of the region (lower, upper) outside of which numbers
// definitely do not round to value (Delta in Grisu3).
template
<
typename
Handler
>
digits
::
result
grisu_gen_digits
(
fp
value
,
uint64_t
error
,
int
&
exp
,
Handler
&
handler
)
{
fp
one
(
1ull
<<
-
value
.
e
,
value
.
e
);
// The integral part of scaled value (p1 in Grisu) = value / one. It cannot be
// zero because it contains a product of two 64-bit numbers with MSB set (due
// to normalization) - 1, shifted right by at most 60 bits.
uint32_t
integral
=
static_cast
<
uint32_t
>
(
value
.
f
>>
-
one
.
e
);
FMT_ASSERT
(
integral
!=
0
,
""
);
FMT_ASSERT
(
integral
==
value
.
f
>>
-
one
.
e
,
""
);
// The fractional part of scaled value (p2 in Grisu) c = value % one.
uint64_t
fractional
=
value
.
f
&
(
one
.
f
-
1
);
exp
=
count_digits
(
integral
);
// kappa in Grisu.
// Divide by 10 to prevent overflow.
auto
result
=
handler
.
on_start
(
data
::
powers_of_10_64
[
exp
-
1
]
<<
-
one
.
e
,
value
.
f
/
10
,
error
*
10
,
exp
);
if
(
result
!=
digits
::
more
)
return
result
;
// Generate digits for the integral part. This can produce up to 10 digits.
do
{
uint32_t
digit
=
0
;
// This optimization by miloyip reduces the number of integer divisions by
// one per iteration.
switch
(
exp
)
{
case
10
:
digit
=
hi
/
1000000000
;
hi
%=
1000000000
;
break
;
case
9
:
digit
=
hi
/
100000000
;
hi
%=
100000000
;
break
;
case
8
:
digit
=
hi
/
10000000
;
hi
%=
10000000
;
break
;
case
7
:
digit
=
hi
/
1000000
;
hi
%=
1000000
;
break
;
case
6
:
digit
=
hi
/
100000
;
hi
%=
100000
;
break
;
case
5
:
digit
=
hi
/
10000
;
hi
%=
10000
;
break
;
case
4
:
digit
=
hi
/
1000
;
hi
%=
1000
;
break
;
case
3
:
digit
=
hi
/
100
;
hi
%=
100
;
break
;
case
2
:
digit
=
hi
/
10
;
hi
%=
10
;
break
;
case
1
:
digit
=
hi
;
hi
=
0
;
break
;
case
10
:
digit
=
integral
/
1000000000
;
integral
%=
1000000000
;
break
;
case
9
:
digit
=
integral
/
100000000
;
integral
%=
100000000
;
break
;
case
8
:
digit
=
integral
/
10000000
;
integral
%=
10000000
;
break
;
case
7
:
digit
=
integral
/
1000000
;
integral
%=
1000000
;
break
;
case
6
:
digit
=
integral
/
100000
;
integral
%=
100000
;
break
;
case
5
:
digit
=
integral
/
10000
;
integral
%=
10000
;
break
;
case
4
:
digit
=
integral
/
1000
;
integral
%=
1000
;
break
;
case
3
:
digit
=
integral
/
100
;
integral
%=
100
;
break
;
case
2
:
digit
=
integral
/
10
;
integral
%=
10
;
break
;
case
1
:
digit
=
integral
;
integral
=
0
;
break
;
default:
FMT_ASSERT
(
false
,
"invalid number of digits"
);
}
if
(
digit
!=
0
||
size
!=
0
)
buf
[
size
++
]
=
static_cast
<
char
>
(
'0'
+
digit
);
--
exp
;
uint64_t
remainder
=
(
static_cast
<
uint64_t
>
(
hi
)
<<
-
one
.
e
)
+
lo
;
if
(
remainder
<=
delta
||
size
>
max_digits
)
{
return
grisu2_round
(
buf
,
size
,
max_digits
,
delta
,
remainder
,
static_cast
<
uint64_t
>
(
data
::
POWERS_OF_10_32
[
exp
])
<<
-
one
.
e
,
diff
.
f
,
exp
);
}
}
// Generate digits for the least significant part (lo).
uint64_t
remainder
=
(
static_cast
<
uint64_t
>
(
integral
)
<<
-
one
.
e
)
+
fractional
;
result
=
handler
.
on_digit
(
static_cast
<
char
>
(
'0'
+
digit
),
data
::
powers_of_10_64
[
exp
]
<<
-
one
.
e
,
remainder
,
error
,
exp
,
true
);
if
(
result
!=
digits
::
more
)
return
result
;
}
while
(
exp
>
0
);
// Generate digits for the fractional part.
for
(;;)
{
lo
*=
10
;
delta
*=
10
;
char
digit
=
static_cast
<
char
>
(
lo
>>
-
one
.
e
);
if
(
digit
!=
0
||
size
!=
0
)
buf
[
size
++
]
=
static_cast
<
char
>
(
'0'
+
digit
);
lo
&=
one
.
f
-
1
;
fractional
*=
10
;
error
*=
10
;
char
digit
=
static_cast
<
char
>
(
'0'
+
static_cast
<
char
>
(
fractional
>>
-
one
.
e
));
fractional
&=
one
.
f
-
1
;
--
exp
;
if
(
lo
<
delta
||
size
>
max_digits
)
{
return
grisu2_round
(
buf
,
size
,
max_digits
,
delta
,
lo
,
one
.
f
,
diff
.
f
*
data
::
POWERS_OF_10_32
[
-
exp
],
exp
);
}
result
=
handler
.
on_digit
(
digit
,
one
.
f
,
fractional
,
error
,
exp
,
false
);
if
(
result
!=
digits
::
more
)
return
result
;
}
}
#if FMT_CLANG_VERSION
# define FMT_FALLTHROUGH [[clang::fallthrough]];
#elif FMT_GCC_VERSION >= 700
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
#else
# define FMT_FALLTHROUGH
#endif
struct
gen_digits_params
{
int
num_digits
;
// The fixed precision digit handler.
struct
fixed_handler
{
char
*
buf
;
int
size
;
int
precision
;
int
exp10
;
bool
fixed
;
bool
upper
;
bool
trailing_zeros
;
};
struct
prettify_handler
{
char
*
data
;
ptrdiff_t
size
;
buffer
&
buf
;
explicit
prettify_handler
(
buffer
&
b
,
ptrdiff_t
n
)
:
data
(
b
.
data
()),
size
(
n
),
buf
(
b
)
{}
~
prettify_handler
()
{
assert
(
buf
.
size
()
>=
to_unsigned
(
size
));
buf
.
resize
(
to_unsigned
(
size
));
}
template
<
typename
F
>
void
insert
(
ptrdiff_t
pos
,
ptrdiff_t
n
,
F
f
)
{
std
::
memmove
(
data
+
pos
+
n
,
data
+
pos
,
to_unsigned
(
size
-
pos
));
f
(
data
+
pos
);
size
+=
n
;
digits
::
result
on_start
(
uint64_t
divisor
,
uint64_t
remainder
,
uint64_t
error
,
int
&
exp
)
{
// Non-fixed formats require at least one digit and no precision adjustment.
if
(
!
fixed
)
return
digits
::
more
;
// Adjust fixed precision by exponent because it is relative to decimal
// point.
precision
+=
exp
+
exp10
;
// Check if precision is satisfied just by leading zeros, e.g.
// format("{:.2f}", 0.001) gives "0.00" without generating any digits.
if
(
precision
>
0
)
return
digits
::
more
;
if
(
precision
<
0
)
return
digits
::
done
;
auto
dir
=
get_round_direction
(
divisor
,
remainder
,
error
);
if
(
dir
==
unknown
)
return
digits
::
error
;
buf
[
size
++
]
=
dir
==
up
?
'1'
:
'0'
;
return
digits
::
done
;
}
digits
::
result
on_digit
(
char
digit
,
uint64_t
divisor
,
uint64_t
remainder
,
uint64_t
error
,
int
,
bool
integral
)
{
FMT_ASSERT
(
remainder
<
divisor
,
""
);
buf
[
size
++
]
=
digit
;
if
(
size
<
precision
)
return
digits
::
more
;
if
(
!
integral
)
{
// Check if error * 2 < divisor with overflow prevention.
// The check is not needed for the integral part because error = 1
// and divisor > (1 << 32) there.
if
(
error
>=
divisor
||
error
>=
divisor
-
error
)
return
digits
::
error
;
}
else
{
FMT_ASSERT
(
error
==
1
&&
divisor
>
2
,
""
);
}
void
insert
(
ptrdiff_t
pos
,
char
c
)
{
std
::
memmove
(
data
+
pos
+
1
,
data
+
pos
,
to_unsigned
(
size
-
pos
));
data
[
pos
]
=
c
;
++
size
;
auto
dir
=
get_round_direction
(
divisor
,
remainder
,
error
);
if
(
dir
!=
up
)
return
dir
==
down
?
digits
::
done
:
digits
::
error
;
++
buf
[
size
-
1
];
for
(
int
i
=
size
-
1
;
i
>
0
&&
buf
[
i
]
>
'9'
;
--
i
)
{
buf
[
i
]
=
'0'
;
++
buf
[
i
-
1
];
}
void
append
(
ptrdiff_t
n
,
char
c
)
{
std
::
uninitialized_fill_n
(
data
+
size
,
n
,
c
);
size
+=
n
;
if
(
buf
[
0
]
>
'9'
)
{
buf
[
0
]
=
'1'
;
buf
[
size
++
]
=
'0'
;
}
void
append
(
char
c
)
{
data
[
size
++
]
=
c
;
}
void
remove_trailing
(
char
c
)
{
while
(
data
[
size
-
1
]
==
c
)
--
size
;
return
digits
::
done
;
}
};
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
template
<
typename
Handler
>
FMT_FUNC
void
write_exponent
(
int
exp
,
Handler
&&
h
)
{
FMT_ASSERT
(
-
1000
<
exp
&&
exp
<
1000
,
"exponent out of range"
);
if
(
exp
<
0
)
{
h
.
append
(
'-'
);
exp
=
-
exp
;
}
else
{
h
.
append
(
'+'
);
}
if
(
exp
>=
100
)
{
h
.
append
(
static_cast
<
char
>
(
'0'
+
exp
/
100
));
exp
%=
100
;
const
char
*
d
=
data
::
DIGITS
+
exp
*
2
;
h
.
append
(
d
[
0
]);
h
.
append
(
d
[
1
]);
}
else
{
const
char
*
d
=
data
::
DIGITS
+
exp
*
2
;
h
.
append
(
d
[
0
]);
h
.
append
(
d
[
1
]);
}
}
// The shortest representation digit handler.
template
<
int
GRISU_VERSION
>
struct
grisu_shortest_handler
{
char
*
buf
;
int
size
;
// Distance between scaled value and upper bound (wp_W in Grisu3).
uint64_t
diff
;
struct
fill
{
size_t
n
;
void
operator
()(
char
*
buf
)
const
{
buf
[
0
]
=
'0'
;
buf
[
1
]
=
'.'
;
std
::
uninitialized_fill_n
(
buf
+
2
,
n
,
'0'
);
digits
::
result
on_start
(
uint64_t
,
uint64_t
,
uint64_t
,
int
&
)
{
return
digits
::
more
;
}
};
// The number is given as v = f * pow(10, exp), where f has size digits.
template
<
typename
Handler
>
FMT_FUNC
void
grisu2_prettify
(
const
gen_digits_params
&
params
,
int
size
,
int
exp
,
Handler
&&
handler
)
{
if
(
!
params
.
fixed
)
{
// Insert a decimal point after the first digit and add an exponent.
handler
.
insert
(
1
,
'.'
);
exp
+=
size
-
1
;
if
(
size
<
params
.
num_digits
)
handler
.
append
(
params
.
num_digits
-
size
,
'0'
);
handler
.
append
(
params
.
upper
?
'E'
:
'e'
);
write_exponent
(
exp
,
handler
);
return
;
}
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
int
full_exp
=
size
+
exp
;
const
int
exp_threshold
=
21
;
if
(
size
<=
full_exp
&&
full_exp
<=
exp_threshold
)
{
// 1234e7 -> 12340000000[.0+]
handler
.
append
(
full_exp
-
size
,
'0'
);
int
num_zeros
=
params
.
num_digits
-
full_exp
;
if
(
num_zeros
>
0
&&
params
.
trailing_zeros
)
{
handler
.
append
(
'.'
);
handler
.
append
(
num_zeros
,
'0'
);
}
}
else
if
(
full_exp
>
0
)
{
// 1234e-2 -> 12.34[0+]
handler
.
insert
(
full_exp
,
'.'
);
if
(
!
params
.
trailing_zeros
)
{
// Remove trailing zeros.
handler
.
remove_trailing
(
'0'
);
}
else
if
(
params
.
num_digits
>
size
)
{
// Add trailing zeros.
ptrdiff_t
num_zeros
=
params
.
num_digits
-
size
;
handler
.
append
(
num_zeros
,
'0'
);
// Decrement the generated number approaching value from above.
void
round
(
uint64_t
d
,
uint64_t
divisor
,
uint64_t
&
remainder
,
uint64_t
error
)
{
while
(
remainder
<
d
&&
error
-
remainder
>=
divisor
&&
(
remainder
+
divisor
<
d
||
d
-
remainder
>=
remainder
+
divisor
-
d
))
{
--
buf
[
size
-
1
];
remainder
+=
divisor
;
}
}
else
{
// 1234e-6 -> 0.001234
handler
.
insert
(
0
,
2
-
full_exp
,
fill
{
to_unsigned
(
-
full_exp
)});
}
}
struct
char_counter
{
ptrdiff_t
size
;
template
<
typename
F
>
void
insert
(
ptrdiff_t
,
ptrdiff_t
n
,
F
)
{
size
+=
n
;
}
void
insert
(
ptrdiff_t
,
char
)
{
++
size
;
}
void
append
(
ptrdiff_t
n
,
char
)
{
size
+=
n
;
}
void
append
(
char
)
{
++
size
;
}
void
remove_trailing
(
char
)
{}
};
// Converts format specifiers into parameters for digit generation and computes
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
// or 0 if exp == 1.
FMT_FUNC
gen_digits_params
process_specs
(
const
core_format_specs
&
specs
,
int
exp
,
buffer
&
buf
)
{
auto
params
=
gen_digits_params
();
int
num_digits
=
specs
.
precision
>=
0
?
specs
.
precision
:
6
;
switch
(
specs
.
type
)
{
case
'G'
:
params
.
upper
=
true
;
FMT_FALLTHROUGH
case
'\0'
:
case
'g'
:
params
.
trailing_zeros
=
(
specs
.
flags
&
HASH_FLAG
)
!=
0
;
if
(
-
4
<=
exp
&&
exp
<
num_digits
+
1
)
{
params
.
fixed
=
true
;
if
(
!
specs
.
type
&&
params
.
trailing_zeros
&&
exp
>=
0
)
num_digits
=
exp
+
1
;
// Implements Grisu's round_weed.
digits
::
result
on_digit
(
char
digit
,
uint64_t
divisor
,
uint64_t
remainder
,
uint64_t
error
,
int
exp
,
bool
integral
)
{
buf
[
size
++
]
=
digit
;
if
(
remainder
>=
error
)
return
digits
::
more
;
if
(
GRISU_VERSION
!=
3
)
{
uint64_t
d
=
integral
?
diff
:
diff
*
data
::
powers_of_10_64
[
-
exp
];
round
(
d
,
divisor
,
remainder
,
error
);
return
digits
::
done
;
}
break
;
case
'F'
:
params
.
upper
=
true
;
FMT_FALLTHROUGH
case
'f'
:
{
params
.
fixed
=
true
;
params
.
trailing_zeros
=
true
;
int
adjusted_min_digits
=
num_digits
+
exp
;
if
(
adjusted_min_digits
>
0
)
num_digits
=
adjusted_min_digits
;
break
;
uint64_t
unit
=
integral
?
1
:
data
::
powers_of_10_64
[
-
exp
];
uint64_t
up
=
(
diff
-
1
)
*
unit
;
// wp_Wup
round
(
up
,
divisor
,
remainder
,
error
);
uint64_t
down
=
(
diff
+
1
)
*
unit
;
// wp_Wdown
if
(
remainder
<
down
&&
error
-
remainder
>=
divisor
&&
(
remainder
+
divisor
<
down
||
down
-
remainder
>
remainder
+
divisor
-
down
))
{
return
digits
::
error
;
}
case
'E'
:
params
.
upper
=
true
;
FMT_FALLTHROUGH
case
'e'
:
++
num_digits
;
break
;
return
2
*
unit
<=
remainder
&&
remainder
<=
error
-
4
*
unit
?
digits
::
done
:
digits
::
error
;
}
params
.
num_digits
=
num_digits
;
char_counter
counter
{
num_digits
};
grisu2_prettify
(
params
,
params
.
num_digits
,
exp
-
num_digits
,
counter
);
buf
.
resize
(
to_unsigned
(
counter
.
size
));
return
params
;
}
};
template
<
typename
Double
>
FMT_FUNC
typename
std
::
enable_if
<
sizeof
(
Double
)
==
sizeof
(
uint64_t
),
bool
>::
type
grisu2_format
(
Double
value
,
buffer
&
buf
,
core_format_specs
specs
)
{
template
<
typename
Double
,
enable_if_t
<
(
sizeof
(
Double
)
==
sizeof
(
uint64_t
)),
int
>
>
FMT_API
bool
grisu_format
(
Double
value
,
buffer
<
char
>&
buf
,
int
precision
,
unsigned
options
,
int
&
exp
)
{
FMT_ASSERT
(
value
>=
0
,
"value is negative"
);
if
(
value
==
0
)
{
gen_digits_params
params
=
process_specs
(
specs
,
1
,
buf
);
const
size_t
size
=
1
;
buf
[
0
]
=
'0'
;
grisu2_prettify
(
params
,
size
,
0
,
prettify_handler
(
buf
,
size
));
bool
fixed
=
(
options
&
grisu_options
::
fixed
)
!=
0
;
if
(
value
<=
0
)
{
// <= instead of == to silence a warning.
if
(
precision
<=
0
||
!
fixed
)
{
exp
=
0
;
buf
.
push_back
(
'0'
);
}
else
{
exp
=
-
precision
;
buf
.
resize
(
precision
);
std
::
uninitialized_fill_n
(
buf
.
data
(),
precision
,
'0'
);
}
return
true
;
}
fp
fp_value
(
value
);
const
int
min_exp
=
-
60
;
// alpha in Grisu.
int
cached_exp10
=
0
;
// K in Grisu.
if
(
precision
!=
-
1
)
{
if
(
precision
>
17
)
return
false
;
fp_value
.
normalize
();
auto
cached_pow
=
get_cached_power
(
min_exp
-
(
fp_value
.
e
+
fp
::
significand_size
),
cached_exp10
);
fp_value
=
fp_value
*
cached_pow
;
fixed_handler
handler
{
buf
.
data
(),
0
,
precision
,
-
cached_exp10
,
fixed
};
if
(
grisu_gen_digits
(
fp_value
,
1
,
exp
,
handler
)
==
digits
::
error
)
return
false
;
buf
.
resize
(
to_unsigned
(
handler
.
size
));
}
else
{
fp
lower
,
upper
;
// w^- and w^+ in the Grisu paper.
fp_value
.
compute_boundaries
(
lower
,
upper
);
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
const
int
min_exp
=
-
60
;
// alpha in Grisu.
int
cached_exp
=
0
;
// K in Grisu.
// Find a cached power of 10 such that multiplying upper by it will bring
// the exponent in the range [min_exp, -32].
auto
cached_pow
=
get_cached_power
(
// \tilde{c}_{-k} in Grisu.
min_exp
-
(
upper
.
e
+
fp
::
significand_size
),
cached_exp
);
cached_exp
=
-
cached_exp
;
upper
=
upper
*
cached_pow
;
// \tilde{M}^+ in Grisu.
--
upper
.
f
;
// \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
fp
one
(
1ull
<<
-
upper
.
e
,
upper
.
e
);
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
// hi = floor(upper / one).
uint32_t
hi
=
static_cast
<
uint32_t
>
(
upper
.
f
>>
-
one
.
e
);
int
exp
=
count_digits
(
hi
);
// kappa in Grisu.
gen_digits_params
params
=
process_specs
(
specs
,
cached_exp
+
exp
,
buf
);
min_exp
-
(
upper
.
e
+
fp
::
significand_size
),
cached_exp10
);
fp_value
.
normalize
();
fp
scaled
_value
=
fp_value
*
cached_pow
;
fp
_value
=
fp_value
*
cached_pow
;
lower
=
lower
*
cached_pow
;
// \tilde{M}^- in Grisu.
++
lower
.
f
;
// \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
uint64_t
delta
=
upper
.
f
-
lower
.
f
;
fp
diff
=
upper
-
scaled_value
;
// wp_w in Grisu.
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
// lo = supper % one.
uint64_t
lo
=
upper
.
f
&
(
one
.
f
-
1
);
upper
=
upper
*
cached_pow
;
// \tilde{M}^+ in Grisu.
assert
(
min_exp
<=
upper
.
e
&&
upper
.
e
<=
-
32
);
auto
result
=
digits
::
result
();
int
size
=
0
;
if
(
!
grisu2_gen_digits
(
buf
.
data
(),
size
,
hi
,
lo
,
exp
,
delta
,
one
,
diff
,
params
.
num_digits
))
{
buf
.
clear
();
return
false
;
if
((
options
&
grisu_options
::
grisu3
)
!=
0
)
{
--
lower
.
f
;
// \tilde{M}^- - 1 ulp -> M^-_{\downarrow}.
++
upper
.
f
;
// \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}.
// Numbers outside of (lower, upper) definitely do not round to value.
grisu_shortest_handler
<
3
>
handler
{
buf
.
data
(),
0
,
(
upper
-
fp_value
).
f
};
result
=
grisu_gen_digits
(
upper
,
upper
.
f
-
lower
.
f
,
exp
,
handler
);
size
=
handler
.
size
;
}
else
{
++
lower
.
f
;
// \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
--
upper
.
f
;
// \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
grisu_shortest_handler
<
2
>
handler
{
buf
.
data
(),
0
,
(
upper
-
fp_value
).
f
};
result
=
grisu_gen_digits
(
upper
,
upper
.
f
-
lower
.
f
,
exp
,
handler
);
size
=
handler
.
size
;
}
grisu2_prettify
(
params
,
size
,
cached_exp
+
exp
,
prettify_handler
(
buf
,
size
));
if
(
result
==
digits
::
error
)
return
false
;
buf
.
resize
(
to_unsigned
(
size
));
}
exp
-=
cached_exp10
;
return
true
;
}
template
<
typename
Double
>
void
sprintf_format
(
Double
value
,
internal
::
buffer
&
buf
,
core_format_specs
spec
)
{
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
;
enum
{
max_format_size
=
10
};
// longest format: %#-*.*Lg
char
format
[
max_format_size
];
char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
if
(
spec
.
has
(
HASH_FLAG
))
*
format_ptr
++
=
'#'
;
if
(
spec
.
precision
>=
0
)
{
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'
;
*
format_ptr
++
=
spec
.
type
;
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
=
FMT_NULL
;
char
*
start
=
nullptr
;
char
*
decimal_point_pos
=
nullptr
;
for
(;;)
{
std
::
size_t
buffer_size
=
buf
.
capacity
();
start
=
&
buf
[
0
];
int
result
=
internal
::
char_traits
<
char
>::
format_float
(
start
,
buffer_size
,
format
,
spec
.
precision
,
value
);
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.
}
...
...
@@ -802,6 +827,7 @@ void sprintf_format(Double value, internal::buffer &buf,
buf
.
reserve
(
buf
.
capacity
()
+
1
);
}
}
return
decimal_point_pos
;
}
}
// namespace internal
...
...
@@ -819,15 +845,13 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
return
;
}
int
length
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
data
(),
s_size
,
FMT_NULL
,
0
);
if
(
length
==
0
)
FMT_THROW
(
windows_error
(
GetLastError
(),
ERROR_MSG
));
int
length
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
data
(),
s_size
,
nullptr
,
0
);
if
(
length
==
0
)
FMT_THROW
(
windows_error
(
GetLastError
(),
ERROR_MSG
));
buffer_
.
resize
(
length
+
1
);
length
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
data
(),
s_size
,
&
buffer_
[
0
],
length
);
if
(
length
==
0
)
FMT_THROW
(
windows_error
(
GetLastError
(),
ERROR_MSG
));
length
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
data
(),
s_size
,
&
buffer_
[
0
],
length
);
if
(
length
==
0
)
FMT_THROW
(
windows_error
(
GetLastError
(),
ERROR_MSG
));
buffer_
[
length
]
=
0
;
}
...
...
@@ -839,8 +863,7 @@ FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
}
FMT_FUNC
int
internal
::
utf16_to_utf8
::
convert
(
wstring_view
s
)
{
if
(
s
.
size
()
>
INT_MAX
)
return
ERROR_INVALID_PARAMETER
;
if
(
s
.
size
()
>
INT_MAX
)
return
ERROR_INVALID_PARAMETER
;
int
s_size
=
static_cast
<
int
>
(
s
.
size
());
if
(
s_size
==
0
)
{
// WideCharToMultiByte does not support zero length, handle separately.
...
...
@@ -849,43 +872,42 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
return
0
;
}
int
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
data
(),
s_size
,
FMT_NULL
,
0
,
FMT_NULL
,
FMT_NULL
);
if
(
length
==
0
)
return
GetLastError
();
int
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
data
(),
s_size
,
nullptr
,
0
,
nullptr
,
nullptr
);
if
(
length
==
0
)
return
GetLastError
();
buffer_
.
resize
(
length
+
1
);
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
data
(),
s_size
,
&
buffer_
[
0
],
length
,
FMT_NULL
,
FMT_NULL
);
if
(
length
==
0
)
return
GetLastError
();
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
data
(),
s_size
,
&
buffer_
[
0
],
length
,
nullptr
,
nullptr
);
if
(
length
==
0
)
return
GetLastError
();
buffer_
[
length
]
=
0
;
return
0
;
}
FMT_FUNC
void
windows_error
::
init
(
int
err_code
,
string_view
format_str
,
format_args
args
)
{
FMT_FUNC
void
windows_error
::
init
(
int
err_code
,
string_view
format_str
,
format_args
args
)
{
error_code_
=
err_code
;
memory_buffer
buffer
;
internal
::
format_windows_error
(
buffer
,
err_code
,
vformat
(
format_str
,
args
));
std
::
runtime_error
&
base
=
*
this
;
std
::
runtime_error
&
base
=
*
this
;
base
=
std
::
runtime_error
(
to_string
(
buffer
));
}
FMT_FUNC
void
internal
::
format_windows_error
(
internal
::
buffer
&
out
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
FMT_FUNC
void
internal
::
format_windows_error
(
internal
::
buffer
<
char
>&
out
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
wmemory_buffer
buf
;
buf
.
resize
(
inline_buffer_size
);
for
(;;)
{
wchar_t
*
system_message
=
&
buf
[
0
];
wchar_t
*
system_message
=
&
buf
[
0
];
int
result
=
FormatMessageW
(
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
FMT_NULL
,
error_code
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
)
,
s
ystem_message
,
static_cast
<
uint32_t
>
(
buf
.
size
()),
FMT_NULL
);
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
nullptr
,
error_code
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
system_message
,
s
tatic_cast
<
uint32_t
>
(
buf
.
size
()),
nullptr
);
if
(
result
!=
0
)
{
utf16_to_utf8
utf8_message
;
if
(
utf8_message
.
convert
(
system_message
)
==
ERROR_SUCCESS
)
{
writer
w
(
out
);
internal
::
writer
w
(
out
);
w
.
write
(
message
);
w
.
write
(
": "
);
w
.
write
(
utf8_message
);
...
...
@@ -897,22 +919,24 @@ FMT_FUNC void internal::format_windows_error(
break
;
// Can't get error message, report error code instead.
buf
.
resize
(
buf
.
size
()
*
2
);
}
}
FMT_CATCH
(...)
{}
}
FMT_CATCH
(...)
{}
format_error_code
(
out
,
error_code
,
message
);
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC
void
format_system_error
(
internal
::
buffer
&
out
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
FMT_FUNC
void
format_system_error
(
internal
::
buffer
<
char
>&
out
,
int
error_code
,
string_view
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
memory_buffer
buf
;
buf
.
resize
(
inline_buffer_size
);
for
(;;)
{
char
*
system_message
=
&
buf
[
0
];
int
result
=
safe_strerror
(
error_code
,
system_message
,
buf
.
size
());
char
*
system_message
=
&
buf
[
0
];
int
result
=
internal
::
safe_strerror
(
error_code
,
system_message
,
buf
.
size
());
if
(
result
==
0
)
{
writer
w
(
out
);
internal
::
writer
w
(
out
);
w
.
write
(
message
);
w
.
write
(
": "
);
w
.
write
(
system_message
);
...
...
@@ -922,37 +946,41 @@ FMT_FUNC void format_system_error(
break
;
// Can't get error message, report error code instead.
buf
.
resize
(
buf
.
size
()
*
2
);
}
}
FMT_CATCH
(...)
{}
}
FMT_CATCH
(...)
{}
format_error_code
(
out
,
error_code
,
message
);
}
FMT_FUNC
void
internal
::
error_handler
::
on_error
(
const
char
*
message
)
{
FMT_FUNC
void
internal
::
error_handler
::
on_error
(
const
char
*
message
)
{
FMT_THROW
(
format_error
(
message
));
}
FMT_FUNC
void
report_system_error
(
int
error_code
,
fmt
::
string_view
message
)
FMT_NOEXCEPT
{
FMT_FUNC
void
report_system_error
(
int
error_code
,
fmt
::
string_view
message
)
FMT_NOEXCEPT
{
report_error
(
format_system_error
,
error_code
,
message
);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC
void
report_windows_error
(
int
error_code
,
fmt
::
string_view
message
)
FMT_NOEXCEPT
{
FMT_FUNC
void
report_windows_error
(
int
error_code
,
fmt
::
string_view
message
)
FMT_NOEXCEPT
{
report_error
(
internal
::
format_windows_error
,
error_code
,
message
);
}
#endif
FMT_FUNC
void
vprint
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
)
{
FMT_FUNC
void
vprint
(
std
::
FILE
*
f
,
string_view
format_str
,
format_args
args
)
{
memory_buffer
buffer
;
internal
::
vformat_to
(
buffer
,
format_str
,
basic_format_args
<
buffer_context
<
char
>
::
type
>
(
args
));
std
::
fwrite
(
buffer
.
data
(),
1
,
buffer
.
size
(),
f
);
basic_format_args
<
buffer_context
<
char
>>
(
args
));
internal
::
fwrite_fully
(
buffer
.
data
(),
1
,
buffer
.
size
(),
f
);
}
FMT_FUNC
void
vprint
(
std
::
FILE
*
f
,
wstring_view
format_str
,
wformat_args
args
)
{
FMT_FUNC
void
vprint
(
std
::
FILE
*
f
,
wstring_view
format_str
,
wformat_args
args
)
{
wmemory_buffer
buffer
;
internal
::
vformat_to
(
buffer
,
format_str
,
args
);
std
::
fwrite
(
buffer
.
data
(),
sizeof
(
wchar_t
),
buffer
.
size
(),
f
);
buffer
.
push_back
(
L'\0'
);
if
(
std
::
fputws
(
buffer
.
data
(),
f
)
==
-
1
)
{
FMT_THROW
(
system_error
(
errno
,
"cannot write to file"
));
}
}
FMT_FUNC
void
vprint
(
string_view
format_str
,
format_args
args
)
{
...
...
include/spdlog/fmt/bundled/format.h
View file @
e149433a
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 @
e149433a
...
...
@@ -8,65 +8,65 @@
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include "format.h"
#include <locale>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace
internal
{
template
<
typename
Char
>
typename
buffer_context
<
Char
>::
type
::
iterator
vformat_to
(
const
std
::
locale
&
loc
,
basic_buffer
<
Char
>
&
buf
,
typename
buffer_context
<
Char
>::
iterator
vformat_to
(
const
std
::
locale
&
loc
,
buffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
typedef
back_insert_range
<
basic_buffer
<
Char
>
>
range
;
return
vformat_to
<
arg_formatter
<
range
>>
(
buf
,
to_string_view
(
format_str
),
args
,
internal
::
locale_ref
(
loc
));
basic_format_args
<
buffer_context
<
Char
>
>
args
)
{
using
range
=
buffer_range
<
Char
>
;
return
vformat_to
<
arg_formatter
<
range
>>
(
buf
,
to_string_view
(
format_str
),
args
,
internal
::
locale_ref
(
loc
));
}
template
<
typename
Char
>
std
::
basic_string
<
Char
>
vformat
(
const
std
::
locale
&
loc
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
std
::
basic_string
<
Char
>
vformat
(
const
std
::
locale
&
loc
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
Char
>
>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
internal
::
vformat_to
(
loc
,
buffer
,
format_str
,
args
);
return
fmt
::
to_string
(
buffer
);
}
}
}
// namespace internal
template
<
typename
S
,
typename
Char
=
FMT_CHAR
(
S
)
>
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
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
const
std
::
locale
&
loc
,
const
S
&
format_str
,
basic_format_args
<
buffer_context
<
Char
>
>
args
)
{
return
internal
::
vformat
(
loc
,
to_string_view
(
format_str
),
args
);
}
template
<
typename
S
,
typename
...
Args
>
inline
std
::
basic_string
<
FMT_CHAR
(
S
)
>
format
(
const
std
::
locale
&
loc
,
const
S
&
format_str
,
const
Args
&
...
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
internal
::
vformat
(
loc
,
to_string_view
(
format_str
),
*
internal
::
checked_args
<
S
,
Args
...
>
(
format_str
,
args
...)
);
{
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...)}
);
}
template
<
typename
String
,
typename
OutputIt
,
typename
...
Args
>
inline
typename
std
::
enable_if
<
internal
::
is_output_iterator
<
OutputIt
>::
value
,
OutputIt
>::
type
vformat_to
(
OutputIt
out
,
const
std
::
locale
&
loc
,
const
String
&
format_str
,
typename
format_args_t
<
OutputIt
,
FMT_CHAR
(
String
)
>::
type
args
)
{
typedef
output_range
<
OutputIt
,
FMT_CHAR
(
String
)
>
range
;
template
<
typename
S
,
typename
OutputIt
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
internal
::
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
<
OutputIt
,
Char
>
args
)
{
using
range
=
internal
::
output_range
<
OutputIt
,
Char
>
;
return
vformat_to
<
arg_formatter
<
range
>>
(
range
(
out
),
to_string_view
(
format_str
),
args
,
internal
::
locale_ref
(
loc
));
}
template
<
typename
OutputIt
,
typename
S
,
typename
...
Args
>
inline
typename
std
::
enable_if
<
internal
::
is_string
<
S
>::
value
&&
internal
::
is_output_iterator
<
OutputIt
>::
value
,
OutputIt
>::
type
format_to
(
OutputIt
out
,
const
std
::
locale
&
loc
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
template
<
typename
OutputIt
,
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
is_output_iterator
<
OutputIt
>
::
value
&&
internal
::
is_string
<
S
>::
value
)
>
inline
OutputIt
format_to
(
OutputIt
out
,
const
std
::
locale
&
loc
,
const
S
&
format_str
,
Args
&&
...
args
)
{
internal
::
check_format_string
<
Args
...
>
(
format_str
);
typedef
typename
format_context_t
<
OutputIt
,
FMT_CHAR
(
S
)
>::
type
context
;
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
),
basic_format_args
<
context
>
(
as
));
...
...
include/spdlog/fmt/bundled/ostream.h
View file @
e149433a
...
...
@@ -8,22 +8,21 @@
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace
internal
{
template
<
class
Char
>
class
formatbuf
:
public
std
::
basic_streambuf
<
Char
>
{
template
<
class
Char
>
class
formatbuf
:
public
std
::
basic_streambuf
<
Char
>
{
private:
typedef
typename
std
::
basic_streambuf
<
Char
>::
int_type
int_type
;
typedef
typename
std
::
basic_streambuf
<
Char
>::
traits_type
traits_type
;
using
int_type
=
typename
std
::
basic_streambuf
<
Char
>::
int_type
;
using
traits_type
=
typename
std
::
basic_streambuf
<
Char
>::
traits_type
;
b
asic_buffer
<
Char
>
&
buffer_
;
b
uffer
<
Char
>&
buffer_
;
public:
formatbuf
(
b
asic_buffer
<
Char
>
&
buffer
)
:
buffer_
(
buffer
)
{}
formatbuf
(
b
uffer
<
Char
>&
buf
)
:
buffer_
(
buf
)
{}
protected:
// The put-area is actually always empty. This makes the implementation
...
...
@@ -39,33 +38,32 @@ class formatbuf : public std::basic_streambuf<Char> {
return
ch
;
}
std
::
streamsize
xsputn
(
const
Char
*
s
,
std
::
streamsize
count
)
FMT_OVERRIDE
{
std
::
streamsize
xsputn
(
const
Char
*
s
,
std
::
streamsize
count
)
FMT_OVERRIDE
{
buffer_
.
append
(
s
,
s
+
count
);
return
count
;
}
};
template
<
typename
Char
>
struct
test_stream
:
std
::
basic_ostream
<
Char
>
{
template
<
typename
Char
>
struct
test_stream
:
std
::
basic_ostream
<
Char
>
{
private:
struct
null
;
// Hide all operator<< from std::basic_ostream<Char>.
void
operator
<<
(
null
);
};
// Checks if T has a user-defined operator<< (e.g. not a member of
std::ostream).
template
<
typename
T
,
typename
Char
>
class
is_streamable
{
// Checks if T has a user-defined operator<< (e.g. not a member of
// std::ostream).
template
<
typename
T
,
typename
Char
>
class
is_streamable
{
private:
template
<
typename
U
>
static
decltype
(
internal
::
declval
<
test_stream
<
Char
>&>
()
<<
internal
::
declval
<
U
>
(),
std
::
true_type
())
test
(
int
);
static
decltype
((
void
)(
std
::
declval
<
test_stream
<
Char
>&>
()
<<
std
::
declval
<
U
>
()),
std
::
true_type
())
test
(
int
);
template
<
typename
>
static
std
::
false_type
test
(...);
template
<
typename
>
static
std
::
false_type
test
(...);
typedef
decltype
(
test
<
T
>
(
0
))
result
;
using
result
=
decltype
(
test
<
T
>
(
0
))
;
public:
static
const
bool
value
=
result
::
value
;
...
...
@@ -73,65 +71,51 @@ class is_streamable {
// Write the content of buf to os.
template
<
typename
Char
>
void
write
(
std
::
basic_ostream
<
Char
>
&
os
,
basic_buffer
<
Char
>
&
buf
)
{
const
Char
*
data
=
buf
.
data
();
typedef
std
::
make_unsigned
<
std
::
streamsize
>::
type
UnsignedStreamSiz
e
;
UnsignedStreamS
ize
size
=
buf
.
size
();
UnsignedStreamS
ize
max_size
=
internal
::
to_unsigned
((
std
::
numeric_limits
<
std
::
streamsize
>::
max
)());
void
write
(
std
::
basic_ostream
<
Char
>
&
os
,
buffer
<
Char
>&
buf
)
{
const
Char
*
buf_
data
=
buf
.
data
();
using
unsigned_streamsize
=
std
::
make_unsigned
<
std
::
streamsize
>::
typ
e
;
unsigned_streams
ize
size
=
buf
.
size
();
unsigned_streams
ize
max_size
=
to_unsigned
((
std
::
numeric_limits
<
std
::
streamsize
>::
max
)());
do
{
UnsignedStreamS
ize
n
=
size
<=
max_size
?
size
:
max_size
;
os
.
write
(
data
,
static_cast
<
std
::
streamsize
>
(
n
));
data
+=
n
;
unsigned_streams
ize
n
=
size
<=
max_size
?
size
:
max_size
;
os
.
write
(
buf_
data
,
static_cast
<
std
::
streamsize
>
(
n
));
buf_
data
+=
n
;
size
-=
n
;
}
while
(
size
!=
0
);
}
template
<
typename
Char
,
typename
T
>
void
format_value
(
b
asic_buffer
<
Char
>
&
buffer
,
const
T
&
value
)
{
internal
::
formatbuf
<
Char
>
format_buf
(
buffer
);
void
format_value
(
b
uffer
<
Char
>&
buf
,
const
T
&
value
)
{
formatbuf
<
Char
>
format_buf
(
buf
);
std
::
basic_ostream
<
Char
>
output
(
&
format_buf
);
output
.
exceptions
(
std
::
ios_base
::
failbit
|
std
::
ios_base
::
badbit
);
output
<<
value
;
buf
fer
.
resize
(
buffer
.
size
());
buf
.
resize
(
buf
.
size
());
}
}
// namespace internal
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template
<
typename
T
,
typename
Char
>
struct
convert_to_int
<
T
,
Char
,
void
>
{
static
const
bool
value
=
convert_to_int
<
T
,
Char
,
int
>::
value
&&
!
internal
::
is_streamable
<
T
,
Char
>::
value
;
};
// Formats an object of type T that has an overloaded ostream operator<<.
template
<
typename
T
,
typename
Char
>
struct
formatter
<
T
,
Char
,
typename
std
::
enable_if
<
internal
::
is_streamable
<
T
,
Char
>::
value
&&
!
internal
::
format_type
<
typename
buffer_context
<
Char
>::
type
,
T
>::
value
>::
type
>
struct
fallback_formatter
<
T
,
Char
,
enable_if_t
<
is_streamable
<
T
,
Char
>::
value
>>
:
formatter
<
basic_string_view
<
Char
>
,
Char
>
{
template
<
typename
Context
>
auto
format
(
const
T
&
value
,
Context
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
format
(
const
T
&
value
,
Context
&
ctx
)
->
decltype
(
ctx
.
out
())
{
basic_memory_buffer
<
Char
>
buffer
;
internal
::
format_value
(
buffer
,
value
);
format_value
(
buffer
,
value
);
basic_string_view
<
Char
>
str
(
buffer
.
data
(),
buffer
.
size
());
return
formatter
<
basic_string_view
<
Char
>
,
Char
>::
format
(
str
,
ctx
);
}
};
}
// namespace internal
template
<
typename
Char
>
inline
void
vprint
(
std
::
basic_ostream
<
Char
>
&
os
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
typename
buffer_context
<
Char
>::
type
>
args
)
{
void
vprint
(
std
::
basic_ostream
<
Char
>&
os
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
buffer_context
<
Char
>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
internal
::
vformat_to
(
buffer
,
format_str
,
args
);
internal
::
write
(
os
,
buffer
);
}
/**
\rst
Prints formatted data to the stream *os*.
...
...
@@ -141,12 +125,11 @@ inline void vprint(std::basic_ostream<Char> &os,
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
typename
std
::
enable_if
<
internal
::
is_string
<
S
>::
value
>::
type
print
(
std
::
basic_ostream
<
FMT_CHAR
(
S
)
>
&
os
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
internal
::
checked_args
<
S
,
Args
...
>
ca
(
format_str
,
args
...);
vprint
(
os
,
to_string_view
(
format_str
),
*
ca
);
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
internal
::
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
),
{
internal
::
make_args_checked
<
Args
...
>
(
format_str
,
args
...)});
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/posix.h
View file @
e149433a
...
...
@@ -69,7 +69,7 @@ FMT_BEGIN_NAMESPACE
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following type
def
s for common character types:
You can use one of the following type
aliase
s for common character types:
+---------------+-----------------------------+
| Type | Definition |
...
...
@@ -89,28 +89,27 @@ FMT_BEGIN_NAMESPACE
format(std::string("{}"), 42);
\endrst
*/
template
<
typename
Char
>
class
basic_cstring_view
{
template
<
typename
Char
>
class
basic_cstring_view
{
private:
const
Char
*
data_
;
const
Char
*
data_
;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view
(
const
Char
*
s
)
:
data_
(
s
)
{}
basic_cstring_view
(
const
Char
*
s
)
:
data_
(
s
)
{}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
())
{}
basic_cstring_view
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
())
{}
/** Returns the pointer to a C string. */
const
Char
*
c_str
()
const
{
return
data_
;
}
const
Char
*
c_str
()
const
{
return
data_
;
}
};
typedef
basic_cstring_view
<
char
>
cstring_view
;
typedef
basic_cstring_view
<
wchar_t
>
wcstring_view
;
using
cstring_view
=
basic_cstring_view
<
char
>
;
using
wcstring_view
=
basic_cstring_view
<
wchar_t
>
;
// An error code.
class
error_code
{
...
...
@@ -126,33 +125,32 @@ class error_code {
// A buffered file.
class
buffered_file
{
private:
FILE
*
file_
;
FILE
*
file_
;
friend
class
file
;
explicit
buffered_file
(
FILE
*
f
)
:
file_
(
f
)
{}
explicit
buffered_file
(
FILE
*
f
)
:
file_
(
f
)
{}
public:
// Constructs a buffered_file object which doesn't represent any file.
buffered_file
()
FMT_NOEXCEPT
:
file_
(
FMT_NULL
)
{}
buffered_file
()
FMT_NOEXCEPT
:
file_
(
nullptr
)
{}
// Destroys the object closing the file it represents if any.
FMT_API
~
buffered_file
()
FMT_NOEXCEPT
;
private:
buffered_file
(
const
buffered_file
&
)
=
delete
;
void
operator
=
(
const
buffered_file
&
)
=
delete
;
buffered_file
(
const
buffered_file
&
)
=
delete
;
void
operator
=
(
const
buffered_file
&
)
=
delete
;
public:
buffered_file
(
buffered_file
&&
other
)
FMT_NOEXCEPT
:
file_
(
other
.
file_
)
{
other
.
file_
=
FMT_NULL
;
buffered_file
(
buffered_file
&&
other
)
FMT_NOEXCEPT
:
file_
(
other
.
file_
)
{
other
.
file_
=
nullptr
;
}
buffered_file
&
operator
=
(
buffered_file
&&
other
)
{
buffered_file
&
operator
=
(
buffered_file
&&
other
)
{
close
();
file_
=
other
.
file_
;
other
.
file_
=
FMT_NULL
;
other
.
file_
=
nullptr
;
return
*
this
;
}
...
...
@@ -163,18 +161,18 @@ class buffered_file {
FMT_API
void
close
();
// Returns the pointer to a FILE object representing this file.
FILE
*
get
()
const
FMT_NOEXCEPT
{
return
file_
;
}
FILE
*
get
()
const
FMT_NOEXCEPT
{
return
file_
;
}
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
FMT_API
int
(
fileno
)()
const
;
FMT_API
int
(
fileno
)()
const
;
void
vprint
(
string_view
format_str
,
format_args
args
)
{
fmt
::
vprint
(
file_
,
format_str
,
args
);
}
template
<
typename
...
Args
>
inline
void
print
(
string_view
format_str
,
const
Args
&
...
args
)
{
inline
void
print
(
string_view
format_str
,
const
Args
&
...
args
)
{
vprint
(
format_str
,
make_format_args
(
args
...));
}
};
...
...
@@ -207,15 +205,13 @@ class file {
FMT_API
file
(
cstring_view
path
,
int
oflag
);
private:
file
(
const
file
&
)
=
delete
;
void
operator
=
(
const
file
&
)
=
delete
;
file
(
const
file
&
)
=
delete
;
void
operator
=
(
const
file
&
)
=
delete
;
public:
file
(
file
&&
other
)
FMT_NOEXCEPT
:
fd_
(
other
.
fd_
)
{
other
.
fd_
=
-
1
;
}
file
(
file
&&
other
)
FMT_NOEXCEPT
:
fd_
(
other
.
fd_
)
{
other
.
fd_
=
-
1
;
}
file
&
operator
=
(
file
&&
other
)
{
file
&
operator
=
(
file
&&
other
)
{
close
();
fd_
=
other
.
fd_
;
other
.
fd_
=
-
1
;
...
...
@@ -236,10 +232,10 @@ class file {
FMT_API
long
long
size
()
const
;
// Attempts to read count bytes from the file into the specified buffer.
FMT_API
std
::
size_t
read
(
void
*
buffer
,
std
::
size_t
count
);
FMT_API
std
::
size_t
read
(
void
*
buffer
,
std
::
size_t
count
);
// Attempts to write count bytes from the specified buffer to the file.
FMT_API
std
::
size_t
write
(
const
void
*
buffer
,
std
::
size_t
count
);
FMT_API
std
::
size_t
write
(
const
void
*
buffer
,
std
::
size_t
count
);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
...
...
@@ -251,68 +247,59 @@ class file {
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API
void
dup2
(
int
fd
,
error_code
&
ec
)
FMT_NOEXCEPT
;
FMT_API
void
dup2
(
int
fd
,
error_code
&
ec
)
FMT_NOEXCEPT
;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
FMT_API
static
void
pipe
(
file
&
read_end
,
file
&
write_end
);
FMT_API
static
void
pipe
(
file
&
read_end
,
file
&
write_end
);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
FMT_API
buffered_file
fdopen
(
const
char
*
mode
);
FMT_API
buffered_file
fdopen
(
const
char
*
mode
);
};
// Returns the memory page size.
long
getpagesize
();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
!defined(__NEWLIB_H__)
# define FMT_LOCALE
#endif
#ifdef FMT_LOCALE
// A "C" numeric locale.
class
Locale
{
private:
#
ifdef _MSC_VER
typedef
_locale_t
locale_t
;
#
ifdef _WIN32
using
locale_t
=
_
locale_t
;
enum
{
LC_NUMERIC_MASK
=
LC_NUMERIC
};
static
locale_t
newlocale
(
int
category_mask
,
const
char
*
locale
,
locale_t
)
{
static
locale_t
newlocale
(
int
category_mask
,
const
char
*
locale
,
locale_t
)
{
return
_create_locale
(
category_mask
,
locale
);
}
static
void
freelocale
(
locale_t
locale
)
{
_free_locale
(
locale
);
}
static
void
freelocale
(
locale_t
locale
)
{
_free_locale
(
locale
);
}
static
double
strtod_l
(
const
char
*
nptr
,
char
**
endptr
,
_locale_t
locale
)
{
static
double
strtod_l
(
const
char
*
nptr
,
char
**
endptr
,
_locale_t
locale
)
{
return
_strtod_l
(
nptr
,
endptr
,
locale
);
}
# endif
locale_t
locale_
;
Locale
(
const
Locale
&
)
=
delete
;
void
operator
=
(
const
Locale
&
)
=
delete
;
Locale
(
const
Locale
&
)
=
delete
;
void
operator
=
(
const
Locale
&
)
=
delete
;
public:
typedef
locale_t
Type
;
using
type
=
locale_t
;
Locale
()
:
locale_
(
newlocale
(
LC_NUMERIC_MASK
,
"C"
,
FMT_NULL
))
{
if
(
!
locale_
)
FMT_THROW
(
system_error
(
errno
,
"cannot create locale"
));
Locale
()
:
locale_
(
newlocale
(
LC_NUMERIC_MASK
,
"C"
,
nullptr
))
{
if
(
!
locale_
)
FMT_THROW
(
system_error
(
errno
,
"cannot create locale"
));
}
~
Locale
()
{
freelocale
(
locale_
);
}
T
ype
get
()
const
{
return
locale_
;
}
t
ype
get
()
const
{
return
locale_
;
}
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double
strtod
(
const
char
*&
str
)
const
{
char
*
end
=
FMT_NULL
;
double
strtod
(
const
char
*&
str
)
const
{
char
*
end
=
nullptr
;
double
result
=
strtod_l
(
str
,
&
end
,
locale_
);
str
=
end
;
return
result
;
...
...
include/spdlog/fmt/bundled/printf.h
View file @
e149433a
...
...
@@ -16,221 +16,90 @@
FMT_BEGIN_NAMESPACE
namespace
internal
{
// An iterator that produces a null terminator on *end. This simplifies parsing
// and allows comparing the performance of processing a null-terminated string
// vs string_view.
template
<
typename
Char
>
class
null_terminating_iterator
{
public:
typedef
std
::
ptrdiff_t
difference_type
;
typedef
Char
value_type
;
typedef
const
Char
*
pointer
;
typedef
const
Char
&
reference
;
typedef
std
::
random_access_iterator_tag
iterator_category
;
null_terminating_iterator
()
:
ptr_
(
0
),
end_
(
0
)
{}
FMT_CONSTEXPR
null_terminating_iterator
(
const
Char
*
ptr
,
const
Char
*
end
)
:
ptr_
(
ptr
),
end_
(
end
)
{}
template
<
typename
Range
>
FMT_CONSTEXPR
explicit
null_terminating_iterator
(
const
Range
&
r
)
:
ptr_
(
r
.
begin
()),
end_
(
r
.
end
())
{}
FMT_CONSTEXPR
null_terminating_iterator
&
operator
=
(
const
Char
*
ptr
)
{
assert
(
ptr
<=
end_
);
ptr_
=
ptr
;
return
*
this
;
}
FMT_CONSTEXPR
Char
operator
*
()
const
{
return
ptr_
!=
end_
?
*
ptr_
:
Char
();
}
FMT_CONSTEXPR
null_terminating_iterator
operator
++
()
{
++
ptr_
;
return
*
this
;
}
FMT_CONSTEXPR
null_terminating_iterator
operator
++
(
int
)
{
null_terminating_iterator
result
(
*
this
);
++
ptr_
;
return
result
;
}
FMT_CONSTEXPR
null_terminating_iterator
operator
--
()
{
--
ptr_
;
return
*
this
;
}
FMT_CONSTEXPR
null_terminating_iterator
operator
+
(
difference_type
n
)
{
return
null_terminating_iterator
(
ptr_
+
n
,
end_
);
}
FMT_CONSTEXPR
null_terminating_iterator
operator
-
(
difference_type
n
)
{
return
null_terminating_iterator
(
ptr_
-
n
,
end_
);
}
FMT_CONSTEXPR
null_terminating_iterator
operator
+=
(
difference_type
n
)
{
ptr_
+=
n
;
return
*
this
;
}
FMT_CONSTEXPR
difference_type
operator
-
(
null_terminating_iterator
other
)
const
{
return
ptr_
-
other
.
ptr_
;
}
FMT_CONSTEXPR
bool
operator
!=
(
null_terminating_iterator
other
)
const
{
return
ptr_
!=
other
.
ptr_
;
}
bool
operator
>=
(
null_terminating_iterator
other
)
const
{
return
ptr_
>=
other
.
ptr_
;
}
// This should be a friend specialization pointer_from<Char> but the latter
// doesn't compile by gcc 5.1 due to a compiler bug.
template
<
typename
CharT
>
friend
FMT_CONSTEXPR_DECL
const
CharT
*
pointer_from
(
null_terminating_iterator
<
CharT
>
it
);
private:
const
Char
*
ptr_
;
const
Char
*
end_
;
};
template
<
typename
T
>
FMT_CONSTEXPR
const
T
*
pointer_from
(
const
T
*
p
)
{
return
p
;
}
template
<
typename
Char
>
FMT_CONSTEXPR
const
Char
*
pointer_from
(
null_terminating_iterator
<
Char
>
it
)
{
return
it
.
ptr_
;
}
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
// that the first character is a digit and presence of a non-digit character at
// the end.
// it: an iterator pointing to the beginning of the input range.
template
<
typename
Iterator
,
typename
ErrorHandler
>
FMT_CONSTEXPR
unsigned
parse_nonnegative_int
(
Iterator
&
it
,
ErrorHandler
&&
eh
)
{
assert
(
'0'
<=
*
it
&&
*
it
<=
'9'
);
if
(
*
it
==
'0'
)
{
++
it
;
return
0
;
}
unsigned
value
=
0
;
// Convert to unsigned to prevent a warning.
unsigned
max_int
=
(
std
::
numeric_limits
<
int
>::
max
)();
unsigned
big
=
max_int
/
10
;
do
{
// Check for overflow.
if
(
value
>
big
)
{
value
=
max_int
+
1
;
break
;
}
value
=
value
*
10
+
unsigned
(
*
it
-
'0'
);
// Workaround for MSVC "setup_exception stack overflow" error:
auto
next
=
it
;
++
next
;
it
=
next
;
}
while
(
'0'
<=
*
it
&&
*
it
<=
'9'
);
if
(
value
>
max_int
)
eh
.
on_error
(
"number is too big"
);
return
value
;
}
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
template
<
typename
T
>
inline
T
const_check
(
T
value
)
{
return
value
;
}
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template
<
bool
IsSigned
>
struct
int_checker
{
template
<
typename
T
>
static
bool
fits_in_int
(
T
value
)
{
template
<
bool
IsSigned
>
struct
int_checker
{
template
<
typename
T
>
static
bool
fits_in_int
(
T
value
)
{
unsigned
max
=
std
::
numeric_limits
<
int
>::
max
();
return
value
<=
max
;
}
static
bool
fits_in_int
(
bool
)
{
return
true
;
}
};
template
<
>
struct
int_checker
<
true
>
{
template
<
typename
T
>
static
bool
fits_in_int
(
T
value
)
{
template
<
>
struct
int_checker
<
true
>
{
template
<
typename
T
>
static
bool
fits_in_int
(
T
value
)
{
return
value
>=
std
::
numeric_limits
<
int
>::
min
()
&&
value
<=
std
::
numeric_limits
<
int
>::
max
();
}
static
bool
fits_in_int
(
int
)
{
return
true
;
}
};
class
printf_precision_handler
:
public
function
<
int
>
{
class
printf_precision_handler
{
public:
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
int
>::
type
operator
()(
T
value
)
{
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
int
operator
()(
T
value
)
{
if
(
!
int_checker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
fits_in_int
(
value
))
FMT_THROW
(
format_error
(
"number is too big"
));
return
static_cast
<
int
>
(
value
);
return
(
std
::
max
)(
static_cast
<
int
>
(
value
),
0
);
}
template
<
typename
T
>
typename
std
::
enable_if
<!
std
::
is_integral
<
T
>::
value
,
int
>::
type
operator
()(
T
)
{
template
<
typename
T
,
FMT_ENABLE_IF
(
!
std
::
is_integral
<
T
>
::
value
)
>
int
operator
()(
T
)
{
FMT_THROW
(
format_error
(
"precision is not integer"
));
return
0
;
}
};
// An argument visitor that returns true iff arg is a zero integer.
class
is_zero_int
:
public
function
<
bool
>
{
class
is_zero_int
{
public:
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
bool
>::
type
operator
()(
T
value
)
{
return
value
==
0
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
bool
operator
()(
T
value
)
{
return
value
==
0
;
}
template
<
typename
T
>
typename
std
::
enable_if
<!
std
::
is_integral
<
T
>::
value
,
bool
>::
type
operator
()(
T
)
{
return
false
;
}
template
<
typename
T
,
FMT_ENABLE_IF
(
!
std
::
is_integral
<
T
>
::
value
)
>
bool
operator
()(
T
)
{
return
false
;
}
};
template
<
typename
T
>
struct
make_unsigned_or_bool
:
std
::
make_unsigned
<
T
>
{};
template
<
typename
T
>
struct
make_unsigned_or_bool
:
std
::
make_unsigned
<
T
>
{};
template
<
>
struct
make_unsigned_or_bool
<
bool
>
{
typedef
bool
type
;
};
template
<
>
struct
make_unsigned_or_bool
<
bool
>
{
using
type
=
bool
;
};
template
<
typename
T
,
typename
Context
>
class
arg_converter
:
public
function
<
void
>
{
template
<
typename
T
,
typename
Context
>
class
arg_converter
{
private:
typedef
typename
Context
::
char_type
Char
;
using
char_type
=
typename
Context
::
char_type
;
basic_format_arg
<
Context
>
&
arg_
;
typename
Context
::
char_type
type_
;
basic_format_arg
<
Context
>
&
arg_
;
char_type
type_
;
public:
arg_converter
(
basic_format_arg
<
Context
>
&
arg
,
Char
type
)
arg_converter
(
basic_format_arg
<
Context
>
&
arg
,
char_type
type
)
:
arg_
(
arg
),
type_
(
type
)
{}
void
operator
()(
bool
value
)
{
if
(
type_
!=
's'
)
operator
()
<
bool
>
(
value
);
if
(
type_
!=
's'
)
operator
()
<
bool
>
(
value
);
}
template
<
typename
U
>
typename
std
::
enable_if
<
std
::
is_integral
<
U
>::
value
>::
type
operator
()(
U
value
)
{
template
<
typename
U
,
FMT_ENABLE_IF
(
std
::
is_integral
<
U
>
::
value
)
>
void
operator
()(
U
value
)
{
bool
is_signed
=
type_
==
'd'
||
type_
==
'i'
;
typedef
typename
std
::
conditional
<
std
::
is_same
<
T
,
void
>::
value
,
U
,
T
>::
type
TargetType
;
if
(
const_check
(
sizeof
(
TargetType
)
<=
sizeof
(
int
)))
{
using
target_type
=
conditional_t
<
std
::
is_same
<
T
,
void
>::
value
,
U
,
T
>
;
if
(
const_check
(
sizeof
(
target_type
)
<=
sizeof
(
int
)))
{
// Extra casts are used to silence warnings.
if
(
is_signed
)
{
arg_
=
internal
::
make_arg
<
Context
>
(
static_cast
<
int
>
(
static_cast
<
TargetT
ype
>
(
value
)));
static_cast
<
int
>
(
static_cast
<
target_t
ype
>
(
value
)));
}
else
{
typedef
typename
make_unsigned_or_bool
<
TargetType
>::
type
Unsigned
;
using
unsigned_type
=
typename
make_unsigned_or_bool
<
target_type
>::
type
;
arg_
=
internal
::
make_arg
<
Context
>
(
static_cast
<
unsigned
>
(
static_cast
<
Unsigned
>
(
value
)));
static_cast
<
unsigned
>
(
static_cast
<
unsigned_type
>
(
value
)));
}
}
else
{
if
(
is_signed
)
{
...
...
@@ -245,10 +114,8 @@ class arg_converter: public function<void> {
}
}
template
<
typename
U
>
typename
std
::
enable_if
<!
std
::
is_integral
<
U
>::
value
>::
type
operator
()(
U
)
{
// No coversion needed for non-integral types.
}
template
<
typename
U
,
FMT_ENABLE_IF
(
!
std
::
is_integral
<
U
>
::
value
)
>
void
operator
()(
U
)
{}
// No conversion needed for non-integral types.
};
// Converts an integer argument to T for printf, if T is an integral type.
...
...
@@ -256,84 +123,77 @@ class arg_converter: public function<void> {
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template
<
typename
T
,
typename
Context
,
typename
Char
>
void
convert_arg
(
basic_format_arg
<
Context
>
&
arg
,
Char
type
)
{
void
convert_arg
(
basic_format_arg
<
Context
>
&
arg
,
Char
type
)
{
visit_format_arg
(
arg_converter
<
T
,
Context
>
(
arg
,
type
),
arg
);
}
// Converts an integer argument to char for printf.
template
<
typename
Context
>
class
char_converter
:
public
function
<
void
>
{
template
<
typename
Context
>
class
char_converter
{
private:
basic_format_arg
<
Context
>
&
arg_
;
basic_format_arg
<
Context
>
&
arg_
;
public:
explicit
char_converter
(
basic_format_arg
<
Context
>
&
arg
)
:
arg_
(
arg
)
{}
explicit
char_converter
(
basic_format_arg
<
Context
>
&
arg
)
:
arg_
(
arg
)
{}
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
>::
type
operator
()(
T
value
)
{
typedef
typename
Context
::
char_type
Char
;
arg_
=
internal
::
make_arg
<
Context
>
(
static_cast
<
Char
>
(
value
));
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
void
operator
()(
T
value
)
{
arg_
=
internal
::
make_arg
<
Context
>
(
static_cast
<
typename
Context
::
char_type
>
(
value
));
}
template
<
typename
T
>
typename
std
::
enable_if
<!
std
::
is_integral
<
T
>::
value
>::
type
operator
()(
T
)
{
// No coversion needed for non-integral types.
}
template
<
typename
T
,
FMT_ENABLE_IF
(
!
std
::
is_integral
<
T
>
::
value
)
>
void
operator
()(
T
)
{}
// No conversion needed for non-integral types.
};
// 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
:
public
function
<
unsigned
>
{
template
<
typename
Char
>
class
printf_width_handler
{
private:
typedef
basic_format_specs
<
Char
>
format_specs
;
using
format_specs
=
basic_format_specs
<
Char
>
;
format_specs
&
spec
_
;
format_specs
&
specs
_
;
public:
explicit
printf_width_handler
(
format_specs
&
spec
)
:
spec_
(
spec
)
{}
explicit
printf_width_handler
(
format_specs
&
specs
)
:
specs_
(
specs
)
{}
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
unsigned
>::
type
operator
()(
T
value
)
{
typedef
typename
internal
::
int_traits
<
T
>::
main_type
UnsignedType
;
UnsignedType
width
=
static_cast
<
UnsignedType
>
(
value
);
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_integral
<
T
>
::
value
)
>
unsigned
operator
()(
T
value
)
{
auto
width
=
static_cast
<
uint32_or_64_t
<
T
>>
(
value
);
if
(
internal
::
is_negative
(
value
))
{
spec
_
.
align_
=
ALIGN_LEFT
;
spec
s_
.
align
=
align
::
left
;
width
=
0
-
width
;
}
unsigned
int_max
=
std
::
numeric_limits
<
int
>::
max
();
if
(
width
>
int_max
)
FMT_THROW
(
format_error
(
"number is too big"
));
if
(
width
>
int_max
)
FMT_THROW
(
format_error
(
"number is too big"
));
return
static_cast
<
unsigned
>
(
width
);
}
template
<
typename
T
>
typename
std
::
enable_if
<!
std
::
is_integral
<
T
>::
value
,
unsigned
>::
type
operator
()(
T
)
{
template
<
typename
T
,
FMT_ENABLE_IF
(
!
std
::
is_integral
<
T
>
::
value
)
>
unsigned
operator
()(
T
)
{
FMT_THROW
(
format_error
(
"width is not integer"
));
return
0
;
}
};
template
<
typename
Char
,
typename
Context
>
void
printf
(
b
asic_buffer
<
Char
>
&
buf
,
basic_string_view
<
Char
>
format
,
void
printf
(
b
uffer
<
Char
>&
buf
,
basic_string_view
<
Char
>
format
,
basic_format_args
<
Context
>
args
)
{
Context
(
std
::
back_inserter
(
buf
),
format
,
args
).
format
();
}
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
();
}
}
// namespace internal
using
internal
::
printf
;
// For printing into memory_buffer.
template
<
typename
Range
>
class
printf_arg_formatter
;
template
<
typename
Range
>
class
printf_arg_formatter
;
template
<
typename
OutputIt
,
typename
Char
,
typename
ArgFormatter
=
printf_arg_formatter
<
back_insert_range
<
internal
::
basic_buffer
<
Char
>
>>>
class
basic_printf_context
;
template
<
typename
OutputIt
,
typename
Char
>
class
basic_printf_context
;
/**
\rst
...
...
@@ -341,61 +201,56 @@ class basic_printf_context;
\endrst
*/
template
<
typename
Range
>
class
printf_arg_formatter
:
public
internal
::
function
<
typename
internal
::
arg_formatter_base
<
Range
>::
iterator
>
,
public
internal
::
arg_formatter_base
<
Range
>
{
class
printf_arg_formatter
:
public
internal
::
arg_formatter_base
<
Range
>
{
public:
using
iterator
=
typename
Range
::
iterator
;
private:
typedef
typename
Range
::
value_type
char_type
;
typedef
decltype
(
internal
::
declval
<
Range
>
().
begin
())
iterator
;
typedef
internal
::
arg_formatter_base
<
Range
>
base
;
typedef
basic_printf_context
<
iterator
,
char_type
>
context_type
;
using
char_type
=
typename
Range
::
value_type
;
using
base
=
internal
::
arg_formatter_base
<
Range
>
;
using
context_type
=
basic_printf_context
<
iterator
,
char_type
>
;
context_type
&
context_
;
context_type
&
context_
;
void
write_null_pointer
(
char
)
{
this
->
spec
()
->
type
=
0
;
this
->
spec
s
()
->
type
=
0
;
this
->
write
(
"(nil)"
);
}
void
write_null_pointer
(
wchar_t
)
{
this
->
spec
()
->
type
=
0
;
this
->
spec
s
()
->
type
=
0
;
this
->
write
(
L"(nil)"
);
}
public:
typedef
typename
base
::
format_specs
format_specs
;
using
format_specs
=
typename
base
::
format_specs
;
/**
\rst
Constructs an argument formatter object.
*buffer* is a reference to the output buffer and *spec* contains format
*buffer* is a reference to the output buffer and *spec
s
* contains format
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter
(
internal
::
basic_buffer
<
char_type
>
&
buffer
,
format_specs
&
spec
,
context_type
&
ctx
)
:
base
(
back_insert_range
<
internal
::
basic_buffer
<
char_type
>>
(
buffer
),
&
spec
,
ctx
.
locale
()),
context_
(
ctx
)
{}
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
iterator
>::
type
operator
()(
T
value
)
{
printf_arg_formatter
(
iterator
iter
,
format_specs
&
specs
,
context_type
&
ctx
)
:
base
(
Range
(
iter
),
&
specs
,
internal
::
locale_ref
()),
context_
(
ctx
)
{}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
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.
if
(
std
::
is_same
<
T
,
bool
>::
value
)
{
format_specs
&
fmt_spec
=
*
this
->
spec
();
if
(
fmt_spec
.
type
!=
's'
)
return
base
::
operator
()(
value
?
1
:
0
);
fmt_spec
.
type
=
0
;
format_specs
&
fmt_specs
=
*
this
->
specs
();
if
(
fmt_specs
.
type
!=
's'
)
return
base
::
operator
()(
value
?
1
:
0
);
fmt_specs
.
type
=
0
;
this
->
write
(
value
!=
0
);
}
else
if
(
std
::
is_same
<
T
,
char_type
>::
value
)
{
format_specs
&
fmt_spec
=
*
this
->
spec
();
if
(
fmt_spec
.
type
&&
fmt_spec
.
type
!=
'c'
)
format_specs
&
fmt_specs
=
*
this
->
specs
();
if
(
fmt_spec
s
.
type
&&
fmt_specs
.
type
!=
'c'
)
return
(
*
this
)(
static_cast
<
int
>
(
value
));
fmt_spec
.
flags
=
0
;
fmt_spec
.
align_
=
ALIGN_RIGHT
;
fmt_specs
.
sign
=
sign
::
none
;
fmt_specs
.
alt
=
false
;
fmt_specs
.
align
=
align
::
right
;
return
base
::
operator
()(
value
);
}
else
{
return
base
::
operator
()(
value
);
...
...
@@ -403,17 +258,16 @@ class printf_arg_formatter:
return
this
->
out
();
}
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_floating_point
<
T
>::
value
,
iterator
>::
type
operator
()(
T
value
)
{
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
T
>
::
value
)
>
iterator
operator
()(
T
value
)
{
return
base
::
operator
()(
value
);
}
/** Formats a null-terminated C string. */
iterator
operator
()(
const
char
*
value
)
{
iterator
operator
()(
const
char
*
value
)
{
if
(
value
)
base
::
operator
()(
value
);
else
if
(
this
->
spec
()
->
type
==
'p'
)
else
if
(
this
->
spec
s
()
->
type
==
'p'
)
write_null_pointer
(
char_type
());
else
this
->
write
(
"(null)"
);
...
...
@@ -421,10 +275,10 @@ class printf_arg_formatter:
}
/** Formats a null-terminated wide C string. */
iterator
operator
()(
const
wchar_t
*
value
)
{
iterator
operator
()(
const
wchar_t
*
value
)
{
if
(
value
)
base
::
operator
()(
value
);
else
if
(
this
->
spec
()
->
type
==
'p'
)
else
if
(
this
->
spec
s
()
->
type
==
'p'
)
write_null_pointer
(
char_type
());
else
this
->
write
(
L"(null)"
);
...
...
@@ -435,68 +289,60 @@ class printf_arg_formatter:
return
base
::
operator
()(
value
);
}
iterator
operator
()(
monostate
value
)
{
return
base
::
operator
()(
value
);
}
iterator
operator
()(
monostate
value
)
{
return
base
::
operator
()(
value
);
}
/** Formats a pointer. */
iterator
operator
()(
const
void
*
value
)
{
if
(
value
)
return
base
::
operator
()(
value
);
this
->
spec
()
->
type
=
0
;
iterator
operator
()(
const
void
*
value
)
{
if
(
value
)
return
base
::
operator
()(
value
);
this
->
specs
()
->
type
=
0
;
write_null_pointer
(
char_type
());
return
this
->
out
();
}
/** Formats an argument of a custom (user-defined) type. */
iterator
operator
()(
typename
basic_format_arg
<
context_type
>::
handle
handle
)
{
handle
.
format
(
context_
);
handle
.
format
(
context_
.
parse_context
(),
context_
);
return
this
->
out
();
}
};
template
<
typename
T
>
struct
printf_formatter
{
template
<
typename
T
>
struct
printf_formatter
{
template
<
typename
ParseContext
>
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
return
ctx
.
begin
();
}
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
return
ctx
.
begin
();
}
template
<
typename
FormatContext
>
auto
format
(
const
T
&
value
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
format
(
const
T
&
value
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
internal
::
format_value
(
internal
::
get_container
(
ctx
.
out
()),
value
);
return
ctx
.
out
();
}
};
/** This template formats data and writes the output to a writer. */
template
<
typename
OutputIt
,
typename
Char
,
typename
ArgFormatter
>
class
basic_printf_context
:
// Inherit publicly as a workaround for the icc bug
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
public
internal
::
context_base
<
OutputIt
,
basic_printf_context
<
OutputIt
,
Char
,
ArgFormatter
>
,
Char
>
{
template
<
typename
OutputIt
,
typename
Char
>
class
basic_printf_context
{
public:
/** The character type for the output. */
typedef
Char
char_type
;
template
<
typename
T
>
struct
formatter_type
{
typedef
printf_formatter
<
T
>
type
;
};
using
char_type
=
Char
;
using
format_arg
=
basic_format_arg
<
basic_printf_context
>
;
template
<
typename
T
>
using
formatter_type
=
printf_formatter
<
T
>
;
private:
typedef
internal
::
context_base
<
OutputIt
,
basic_printf_context
,
Char
>
base
;
typedef
typename
base
::
format_arg
format_arg
;
typedef
basic_format_specs
<
char_type
>
format_specs
;
typedef
internal
::
null_terminating_iterator
<
char_type
>
iterator
;
using
format_specs
=
basic_format_specs
<
char_type
>
;
OutputIt
out_
;
basic_format_args
<
basic_printf_context
>
args_
;
basic_parse_context
<
Char
>
parse_ctx_
;
void
parse_flags
(
format_specs
&
spec
,
iterator
&
it
);
static
void
parse_flags
(
format_specs
&
specs
,
const
Char
*&
it
,
const
Char
*
end
);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
format_arg
get_arg
(
iterator
it
,
unsigned
arg_index
=
(
std
::
numeric_limits
<
unsigned
>::
max
)());
format_arg
get_arg
(
unsigned
arg_index
=
std
::
numeric_limits
<
unsigned
>::
max
());
// Parses argument index, flags and width and returns the argument index.
unsigned
parse_header
(
iterator
&
it
,
format_specs
&
spec
);
unsigned
parse_header
(
const
Char
*&
it
,
const
Char
*
end
,
format_specs
&
specs
);
public:
/**
...
...
@@ -508,160 +354,180 @@ class basic_printf_context :
*/
basic_printf_context
(
OutputIt
out
,
basic_string_view
<
char_type
>
format_str
,
basic_format_args
<
basic_printf_context
>
args
)
:
base
(
out
,
format_str
,
args
)
{}
:
out_
(
out
),
args_
(
args
),
parse_ctx_
(
format_str
)
{}
OutputIt
out
()
{
return
out_
;
}
void
advance_to
(
OutputIt
it
)
{
out_
=
it
;
}
format_arg
arg
(
unsigned
id
)
const
{
return
args_
.
get
(
id
);
}
using
base
::
parse_context
;
using
base
::
out
;
using
base
::
advance_to
;
basic_parse_context
<
Char
>&
parse_context
()
{
return
parse_ctx_
;
}
FMT_CONSTEXPR
void
on_error
(
const
char
*
message
)
{
parse_ctx_
.
on_error
(
message
);
}
/** Formats stored arguments and writes the output to the range. */
void
format
();
template
<
typename
ArgFormatter
=
printf_arg_formatter
<
internal
::
buffer_range
<
Char
>
>>
OutputIt
format
();
};
template
<
typename
OutputIt
,
typename
Char
,
typename
AF
>
void
basic_printf_context
<
OutputIt
,
Char
,
AF
>::
parse_flags
(
format_specs
&
spec
,
iterator
&
it
)
{
for
(;;)
{
switch
(
*
it
++
)
{
template
<
typename
OutputIt
,
typename
Char
>
void
basic_printf_context
<
OutputIt
,
Char
>::
parse_flags
(
format_specs
&
specs
,
const
Char
*&
it
,
const
Char
*
end
)
{
for
(;
it
!=
end
;
++
it
)
{
switch
(
*
it
)
{
case
'-'
:
spec
.
align_
=
ALIGN_LEFT
;
specs
.
align
=
align
::
left
;
break
;
case
'+'
:
spec
.
flags
|=
SIGN_FLAG
|
PLUS_FLAG
;
specs
.
sign
=
sign
::
plus
;
break
;
case
'0'
:
spec
.
fill_
=
'0'
;
specs
.
fill
[
0
]
=
'0'
;
break
;
case
' '
:
spec
.
flags
|=
SIGN_FLAG
;
specs
.
sign
=
sign
::
space
;
break
;
case
'#'
:
spec
.
flags
|=
HASH_FLAG
;
specs
.
alt
=
true
;
break
;
default:
--
it
;
return
;
}
}
}
template
<
typename
OutputIt
,
typename
Char
,
typename
AF
>
typename
basic_printf_context
<
OutputIt
,
Char
,
AF
>::
format_arg
basic_printf_context
<
OutputIt
,
Char
,
AF
>::
get_arg
(
iterator
it
,
unsigned
arg_index
)
{
(
void
)
it
;
template
<
typename
OutputIt
,
typename
Char
>
typename
basic_printf_context
<
OutputIt
,
Char
>::
format_arg
basic_printf_context
<
OutputIt
,
Char
>::
get_arg
(
unsigned
arg_index
)
{
if
(
arg_index
==
std
::
numeric_limits
<
unsigned
>::
max
())
return
this
->
do_get_arg
(
this
->
parse_context
().
next_arg_id
());
return
base
::
get_arg
(
arg_index
-
1
);
arg_index
=
parse_ctx_
.
next_arg_id
();
else
parse_ctx_
.
check_arg_id
(
--
arg_index
);
return
internal
::
get_arg
(
*
this
,
arg_index
);
}
template
<
typename
OutputIt
,
typename
Char
,
typename
AF
>
unsigned
basic_printf_context
<
OutputIt
,
Char
,
AF
>::
parse_header
(
iterator
&
it
,
format_specs
&
spec
)
{
template
<
typename
OutputIt
,
typename
Char
>
unsigned
basic_printf_context
<
OutputIt
,
Char
>::
parse_header
(
const
Char
*&
it
,
const
Char
*
end
,
format_specs
&
specs
)
{
unsigned
arg_index
=
std
::
numeric_limits
<
unsigned
>::
max
();
char_type
c
=
*
it
;
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
internal
::
error_handler
eh
;
unsigned
value
=
parse_nonnegative_int
(
it
,
eh
);
if
(
*
it
==
'$'
)
{
// value is an argument index
unsigned
value
=
parse_nonnegative_int
(
it
,
e
nd
,
e
h
);
if
(
it
!=
end
&&
*
it
==
'$'
)
{
// value is an argument index
++
it
;
arg_index
=
value
;
}
else
{
if
(
c
==
'0'
)
spec
.
fill_
=
'0'
;
if
(
c
==
'0'
)
specs
.
fill
[
0
]
=
'0'
;
if
(
value
!=
0
)
{
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec
.
width_
=
value
;
spec
s
.
width
=
value
;
return
arg_index
;
}
}
}
parse_flags
(
spec
,
it
);
parse_flags
(
spec
s
,
it
,
end
);
// Parse width.
if
(
it
!=
end
)
{
if
(
*
it
>=
'0'
&&
*
it
<=
'9'
)
{
internal
::
error_handler
eh
;
spec
.
width_
=
parse_nonnegative_int
(
it
,
eh
);
specs
.
width
=
parse_nonnegative_int
(
it
,
end
,
eh
);
}
else
if
(
*
it
==
'*'
)
{
++
it
;
spec
.
width_
=
visit_format_arg
(
internal
::
printf_width_handler
<
char_type
>
(
spec
),
get_arg
(
it
));
specs
.
width
=
visit_format_arg
(
internal
::
printf_width_handler
<
char_type
>
(
specs
),
get_arg
());
}
}
return
arg_index
;
}
template
<
typename
OutputIt
,
typename
Char
,
typename
AF
>
void
basic_printf_context
<
OutputIt
,
Char
,
AF
>::
format
()
{
auto
&
buffer
=
internal
::
get_container
(
this
->
out
());
auto
start
=
iterator
(
this
->
parse_context
());
template
<
typename
OutputIt
,
typename
Char
>
template
<
typename
ArgFormatter
>
OutputIt
basic_printf_context
<
OutputIt
,
Char
>::
format
()
{
auto
out
=
this
->
out
();
const
Char
*
start
=
parse_ctx_
.
begin
();
const
Char
*
end
=
parse_ctx_
.
end
();
auto
it
=
start
;
using
internal
::
pointer_from
;
while
(
*
it
)
{
while
(
it
!=
end
)
{
char_type
c
=
*
it
++
;
if
(
c
!=
'%'
)
continue
;
if
(
*
it
==
c
)
{
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
)
);
if
(
it
!=
end
&&
*
it
==
c
)
{
out
=
std
::
copy
(
start
,
it
,
out
);
start
=
++
it
;
continue
;
}
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
)
-
1
);
out
=
std
::
copy
(
start
,
it
-
1
,
out
);
format_specs
spec
;
spec
.
align_
=
ALIGN_RIGHT
;
format_specs
spec
s
;
spec
s
.
align
=
align
::
right
;
// Parse argument index, flags and width.
unsigned
arg_index
=
parse_header
(
it
,
spec
);
unsigned
arg_index
=
parse_header
(
it
,
end
,
specs
);
// Parse precision.
if
(
*
it
==
'.'
)
{
if
(
it
!=
end
&&
*
it
==
'.'
)
{
++
it
;
if
(
'0'
<=
*
it
&&
*
it
<=
'9'
)
{
c
=
it
!=
end
?
*
it
:
0
;
if
(
'0'
<=
c
&&
c
<=
'9'
)
{
internal
::
error_handler
eh
;
spec
.
precision
=
static_cast
<
int
>
(
parse_nonnegative_int
(
it
,
eh
));
}
else
if
(
*
it
==
'*'
)
{
spec
s
.
precision
=
static_cast
<
int
>
(
parse_nonnegative_int
(
it
,
end
,
eh
));
}
else
if
(
c
==
'*'
)
{
++
it
;
spec
.
precision
=
visit_format_arg
(
internal
::
printf_precision_handler
(),
get_arg
(
it
));
spec
s
.
precision
=
visit_format_arg
(
internal
::
printf_precision_handler
(),
get_arg
());
}
else
{
spec
.
precision
=
0
;
spec
s
.
precision
=
0
;
}
}
format_arg
arg
=
get_arg
(
it
,
arg_index
);
if
(
spec
.
has
(
HASH_FLAG
)
&&
visit_format_arg
(
internal
::
is_zero_int
(),
arg
))
spec
.
flags
=
static_cast
<
uint_least8_t
>
(
spec
.
flags
&
(
~
internal
::
to_unsigned
<
int
>
(
HASH_FLAG
)))
;
if
(
spec
.
fill_
==
'0'
)
{
format_arg
arg
=
get_arg
(
arg_index
);
if
(
spec
s
.
alt
&&
visit_format_arg
(
internal
::
is_zero_int
(),
arg
))
spec
s
.
alt
=
false
;
if
(
spec
s
.
fill
[
0
]
==
'0'
)
{
if
(
arg
.
is_arithmetic
())
spec
.
align_
=
ALIGN_NUMERIC
;
spec
s
.
align
=
align
::
numeric
;
else
spec
.
fill_
=
' '
;
// Ignore '0' flag for non-numeric types.
spec
s
.
fill
[
0
]
=
' '
;
// Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
c
=
it
!=
end
?
*
it
++
:
0
;
char_type
t
=
it
!=
end
?
*
it
:
0
;
using
internal
::
convert_arg
;
switch
(
*
it
++
)
{
switch
(
c
)
{
case
'h'
:
if
(
*
it
==
'h'
)
convert_arg
<
signed
char
>
(
arg
,
*++
it
);
else
convert_arg
<
short
>
(
arg
,
*
it
);
if
(
t
==
'h'
)
{
++
it
;
t
=
it
!=
end
?
*
it
:
0
;
convert_arg
<
signed
char
>
(
arg
,
t
);
}
else
{
convert_arg
<
short
>
(
arg
,
t
);
}
break
;
case
'l'
:
if
(
*
it
==
'l'
)
convert_arg
<
long
long
>
(
arg
,
*++
it
);
else
convert_arg
<
long
>
(
arg
,
*
it
);
if
(
t
==
'l'
)
{
++
it
;
t
=
it
!=
end
?
*
it
:
0
;
convert_arg
<
long
long
>
(
arg
,
t
);
}
else
{
convert_arg
<
long
>
(
arg
,
t
);
}
break
;
case
'j'
:
convert_arg
<
intmax_t
>
(
arg
,
*
i
t
);
convert_arg
<
intmax_t
>
(
arg
,
t
);
break
;
case
'z'
:
convert_arg
<
std
::
size_t
>
(
arg
,
*
i
t
);
convert_arg
<
std
::
size_t
>
(
arg
,
t
);
break
;
case
't'
:
convert_arg
<
std
::
ptrdiff_t
>
(
arg
,
*
i
t
);
convert_arg
<
std
::
ptrdiff_t
>
(
arg
,
t
);
break
;
case
'L'
:
// printf produces garbage when 'L' is omitted for long double, no
...
...
@@ -669,23 +535,22 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
break
;
default:
--
it
;
convert_arg
<
void
>
(
arg
,
*
it
);
convert_arg
<
void
>
(
arg
,
c
);
}
// Parse type.
if
(
!*
it
)
FMT_THROW
(
format_error
(
"invalid format string"
));
spec
.
type
=
static_cast
<
char
>
(
*
it
++
);
if
(
it
==
end
)
FMT_THROW
(
format_error
(
"invalid format string"
));
specs
.
type
=
static_cast
<
char
>
(
*
it
++
);
if
(
arg
.
is_integral
())
{
// Normalize type.
switch
(
spec
.
type
)
{
case
'i'
:
case
'u'
:
spec
.
type
=
'd'
;
switch
(
specs
.
type
)
{
case
'i'
:
case
'u'
:
specs
.
type
=
'd'
;
break
;
case
'c'
:
// TODO: handle wchar_t better?
visit_format_arg
(
internal
::
char_converter
<
basic_printf_context
>
(
arg
),
arg
);
visit_format_arg
(
internal
::
char_converter
<
basic_printf_context
>
(
arg
),
arg
);
break
;
}
}
...
...
@@ -693,22 +558,21 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
start
=
it
;
// Format argument.
visit_format_arg
(
A
F
(
buffer
,
spec
,
*
this
),
arg
);
visit_format_arg
(
A
rgFormatter
(
out
,
specs
,
*
this
),
arg
);
}
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
)
);
return
std
::
copy
(
start
,
it
,
out
);
}
template
<
typename
Buffer
>
struct
basic_printf_context_t
{
typedef
basic_printf_context
<
std
::
back_insert_iterator
<
Buffer
>
,
typename
Buffer
::
value_type
>
type
;
};
template
<
typename
Char
>
using
basic_printf_context_t
=
basic_printf_context
<
std
::
back_insert_iterator
<
internal
::
buffer
<
Char
>>
,
Char
>
;
typedef
basic_printf_context_t
<
internal
::
buffer
>::
type
printf_context
;
typedef
basic_printf_context_t
<
internal
::
wbuffer
>::
type
wprintf_context
;
using
printf_context
=
basic_printf_context_t
<
char
>
;
using
wprintf_context
=
basic_printf_context_t
<
wchar_t
>
;
typedef
basic_format_args
<
printf_context
>
printf_args
;
typedef
basic_format_args
<
wprintf_context
>
wprintf_args
;
using
printf_args
=
basic_format_args
<
printf_context
>
;
using
wprintf_args
=
basic_format_args
<
wprintf_context
>
;
/**
\rst
...
...
@@ -716,9 +580,11 @@ typedef basic_format_args<wprintf_context> wprintf_args;
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
template
<
typename
...
Args
>
inline
format_arg_store
<
printf_context
,
Args
...
>
make_printf_args
(
const
Args
&
...
args
)
{
return
{
args
...};
}
template
<
typename
...
Args
>
inline
format_arg_store
<
printf_context
,
Args
...
>
make_printf_args
(
const
Args
&
...
args
)
{
return
{
args
...};
}
/**
\rst
...
...
@@ -726,15 +592,15 @@ inline format_arg_store<printf_context, Args...>
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
template
<
typename
...
Args
>
inline
format_arg_store
<
wprintf_context
,
Args
...
>
make_wprintf_args
(
const
Args
&
...
args
)
{
return
{
args
...};
}
template
<
typename
S
,
typename
Char
=
FMT_CHAR
(
S
)>
inline
std
::
basic_string
<
Char
>
vsprintf
(
const
S
&
format
,
basic_format_args
<
typename
basic_printf_context_t
<
internal
::
basic_buffer
<
Char
>>::
type
>
args
)
{
template
<
typename
...
Args
>
inline
format_arg_store
<
wprintf_context
,
Args
...
>
make_wprintf_args
(
const
Args
&
...
args
)
{
return
{
args
...};
}
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
std
::
basic_string
<
Char
>
vsprintf
(
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
Char
>
>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
printf
(
buffer
,
to_string_view
(
format
),
args
);
return
to_string
(
buffer
);
...
...
@@ -749,27 +615,22 @@ vsprintf(const S &format,
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
std
::
basic_string
<
FMT_CHAR
(
S
)
>
)
sprintf
(
const
S
&
format
,
const
Args
&
...
args
)
{
internal
::
check_format_string
<
Args
...
>
(
format
);
typedef
internal
::
basic_buffer
<
FMT_CHAR
(
S
)
>
buffer
;
typedef
typename
basic_printf_context_t
<
buffer
>::
type
context
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...
};
return
vsprintf
(
to_string_view
(
format
),
basic_format_args
<
context
>
(
as
));
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
internal
::
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
...)});
}
template
<
typename
S
,
typename
Char
=
FMT_CHAR
(
S
)>
inline
int
vfprintf
(
std
::
FILE
*
f
,
const
S
&
format
,
basic_format_args
<
typename
basic_printf_context_t
<
internal
::
basic_buffer
<
Char
>>::
type
>
args
)
{
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
int
vfprintf
(
std
::
FILE
*
f
,
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
Char
>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
printf
(
buffer
,
to_string_view
(
format
),
args
);
std
::
size_t
size
=
buffer
.
size
();
return
std
::
fwrite
(
buffer
.
data
(),
sizeof
(
Char
),
size
,
f
)
<
size
?
-
1
:
static_cast
<
int
>
(
size
);
return
std
::
fwrite
(
buffer
.
data
(),
sizeof
(
Char
),
size
,
f
)
<
size
?
-
1
:
static_cast
<
int
>
(
size
);
}
/**
...
...
@@ -781,21 +642,17 @@ inline int vfprintf(std::FILE *f, const S &format,
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
int
)
fprintf
(
std
::
FILE
*
f
,
const
S
&
format
,
const
Args
&
...
args
)
{
internal
::
check_format_string
<
Args
...
>
(
format
);
typedef
internal
::
basic_buffer
<
FMT_CHAR
(
S
)
>
buffer
;
typedef
typename
basic_printf_context_t
<
buffer
>::
type
context
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...
};
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
enable_if_t
<
internal
::
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
),
basic_format_args
<
context
>
(
as
)
);
{
make_format_args
<
context
>
(
args
...)}
);
}
template
<
typename
S
,
typename
Char
=
FMT_CHAR
(
S
)>
inline
int
vprintf
(
const
S
&
format
,
basic_format_args
<
typename
basic_printf_context_t
<
internal
::
basic_buffer
<
Char
>>::
type
>
args
)
{
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
int
vprintf
(
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
Char
>>
args
)
{
return
vfprintf
(
stdout
,
to_string_view
(
format
),
args
);
}
...
...
@@ -808,28 +665,35 @@ inline int vprintf(const S &format,
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
int
)
printf
(
const
S
&
format_str
,
const
Args
&
...
args
)
{
internal
::
check_format_string
<
Args
...
>
(
format_str
);
typedef
internal
::
basic_buffer
<
FMT_CHAR
(
S
)
>
buffer
;
typedef
typename
basic_printf_context_t
<
buffer
>::
type
context
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...
};
template
<
typename
S
,
typename
...
Args
,
FMT_ENABLE_IF
(
internal
::
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
),
basic_format_args
<
context
>
(
as
)
);
{
make_format_args
<
context
>
(
args
...)}
);
}
template
<
typename
S
,
typename
Char
=
FMT_CHAR
(
S
)>
inline
int
vfprintf
(
std
::
basic_ostream
<
Char
>
&
os
,
const
S
&
format
,
basic_format_args
<
typename
basic_printf_context_t
<
internal
::
basic_buffer
<
Char
>>::
type
>
args
)
{
template
<
typename
S
,
typename
Char
=
char_t
<
S
>
>
inline
int
vfprintf
(
std
::
basic_ostream
<
Char
>&
os
,
const
S
&
format
,
basic_format_args
<
basic_printf_context_t
<
Char
>>
args
)
{
basic_memory_buffer
<
Char
>
buffer
;
printf
(
buffer
,
to_string_view
(
format
),
args
);
internal
::
write
(
os
,
buffer
);
return
static_cast
<
int
>
(
buffer
.
size
());
}
/** Formats arguments and writes the output to the range. */
template
<
typename
ArgFormatter
,
typename
Char
,
typename
Context
=
basic_printf_context
<
typename
ArgFormatter
::
iterator
,
Char
>
>
typename
ArgFormatter
::
iterator
vprintf
(
internal
::
buffer
<
Char
>&
out
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
Context
>
args
)
{
typename
ArgFormatter
::
iterator
iter
(
out
);
Context
(
iter
,
format_str
,
args
).
template
format
<
ArgFormatter
>();
return
iter
;
}
/**
\rst
Prints formatted data to the stream *os*.
...
...
@@ -839,16 +703,12 @@ inline int vfprintf(std::basic_ostream<Char> &os,
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template
<
typename
S
,
typename
...
Args
>
inline
FMT_ENABLE_IF_T
(
internal
::
is_string
<
S
>::
value
,
int
)
fprintf
(
std
::
basic_ostream
<
FMT_CHAR
(
S
)
>
&
os
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
internal
::
check_format_string
<
Args
...
>
(
format_str
);
typedef
internal
::
basic_buffer
<
FMT_CHAR
(
S
)
>
buffer
;
typedef
typename
basic_printf_context_t
<
buffer
>::
type
context
;
format_arg_store
<
context
,
Args
...
>
as
{
args
...
};
template
<
typename
S
,
typename
...
Args
,
typename
Char
=
char_t
<
S
>
>
inline
int
fprintf
(
std
::
basic_ostream
<
Char
>&
os
,
const
S
&
format_str
,
const
Args
&
...
args
)
{
using
context
=
basic_printf_context_t
<
Char
>
;
return
vfprintf
(
os
,
to_string_view
(
format_str
),
basic_format_args
<
context
>
(
as
)
);
{
make_format_args
<
context
>
(
args
...)}
);
}
FMT_END_NAMESPACE
...
...
include/spdlog/fmt/bundled/ranges.h
View file @
e149433a
// Formatting library for C++ -
the core API
// Formatting library for C++ -
experimental range support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
...
...
@@ -12,8 +12,8 @@
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include "format.h"
#include <type_traits>
#include "format.h"
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
...
...
@@ -22,10 +22,9 @@
FMT_BEGIN_NAMESPACE
template
<
typename
Char
>
struct
formatting_base
{
template
<
typename
Char
>
struct
formatting_base
{
template
<
typename
ParseContext
>
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
return
ctx
.
begin
();
}
};
...
...
@@ -33,7 +32,8 @@ struct formatting_base {
template
<
typename
Char
,
typename
Enable
=
void
>
struct
formatting_range
:
formatting_base
<
Char
>
{
static
FMT_CONSTEXPR_DECL
const
std
::
size_t
range_length_limit
=
FMT_RANGE_OUTPUT_LENGTH_LIMIT
;
// output only up to N items from the range.
FMT_RANGE_OUTPUT_LENGTH_LIMIT
;
// output only up to N items from the
// range.
Char
prefix
;
Char
delimiter
;
Char
postfix
;
...
...
@@ -55,87 +55,78 @@ struct formatting_tuple : formatting_base<Char> {
namespace
internal
{
template
<
typename
RangeT
,
typename
OutputIterator
>
void
copy
(
const
RangeT
&
range
,
OutputIterator
out
)
{
OutputIterator
copy
(
const
RangeT
&
range
,
OutputIterator
out
)
{
for
(
auto
it
=
range
.
begin
(),
end
=
range
.
end
();
it
!=
end
;
++
it
)
*
out
++
=
*
it
;
return
out
;
}
template
<
typename
OutputIterator
>
void
copy
(
const
char
*
str
,
OutputIterator
out
)
{
const
char
*
p_curr
=
str
;
while
(
*
p_curr
)
{
*
out
++
=
*
p_curr
++
;
}
OutputIterator
copy
(
const
char
*
str
,
OutputIterator
out
)
{
while
(
*
str
)
*
out
++
=
*
str
++
;
return
out
;
}
template
<
typename
OutputIterator
>
void
copy
(
char
ch
,
OutputIterator
out
)
{
OutputIterator
copy
(
char
ch
,
OutputIterator
out
)
{
*
out
++
=
ch
;
return
out
;
}
/// Return true value if T has std::string interface, like std::string_view.
template
<
typename
T
>
class
is_like_std_string
{
template
<
typename
T
>
class
is_like_std_string
{
template
<
typename
U
>
static
auto
check
(
U
*
p
)
->
decltype
(
p
->
find
(
'a'
),
p
->
length
(),
p
->
data
(),
int
());
template
<
typename
>
static
void
check
(...);
static
auto
check
(
U
*
p
)
->
decltype
((
void
)
p
->
find
(
'a'
),
p
->
length
(),
(
void
)
p
->
data
(),
int
());
template
<
typename
>
static
void
check
(...);
public:
static
FMT_CONSTEXPR_DECL
const
bool
value
=
!
std
::
is_void
<
decltype
(
check
<
T
>
(
FMT_NULL
))
>::
value
;
is_string
<
T
>::
value
||
!
std
::
is_void
<
decltype
(
check
<
T
>
(
nullptr
))
>::
value
;
};
template
<
typename
Char
>
struct
is_like_std_string
<
fmt
::
basic_string_view
<
Char
>>
:
std
::
true_type
{};
template
<
typename
...
Ts
>
struct
conditional_helper
{};
template
<
typename
...
Ts
>
struct
conditional_helper
{};
template
<
typename
T
,
typename
_
=
void
>
struct
is_range_
:
std
::
false_type
{};
template
<
typename
T
,
typename
_
=
void
>
struct
is_range_
:
std
::
false_type
{};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
template
<
typename
T
>
struct
is_range_
<
T
,
typename
std
::
conditional
<
false
,
conditional_helper
<
decltype
(
internal
::
declval
<
T
>
().
begin
()),
decltype
(
internal
::
declval
<
T
>
().
end
())
>
,
void
>::
type
>
:
std
::
true_type
{};
struct
is_range_
<
T
,
conditional_t
<
false
,
conditional_helper
<
decltype
(
std
::
declval
<
T
>
().
begin
()),
decltype
(
std
::
declval
<
T
>
().
end
())
>
,
void
>
>
:
std
::
true_type
{};
#endif
/// tuple_size and tuple_element check.
template
<
typename
T
>
class
is_tuple_like_
{
template
<
typename
T
>
class
is_tuple_like_
{
template
<
typename
U
>
static
auto
check
(
U
*
p
)
->
decltype
(
std
::
tuple_size
<
U
>::
value
,
internal
::
declval
<
typename
std
::
tuple_element
<
0
,
U
>::
type
>
(),
int
());
template
<
typename
>
static
void
check
(...);
static
auto
check
(
U
*
p
)
->
decltype
(
std
::
tuple_size
<
U
>::
value
,
(
void
)
std
::
declval
<
typename
std
::
tuple_element
<
0
,
U
>::
type
>
(),
int
());
template
<
typename
>
static
void
check
(...);
public:
static
FMT_CONSTEXPR_DECL
const
bool
value
=
!
std
::
is_void
<
decltype
(
check
<
T
>
(
FMT_NULL
))
>::
value
;
!
std
::
is_void
<
decltype
(
check
<
T
>
(
nullptr
))
>::
value
;
};
// Check for integer_sequence
#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
index_sequence
=
std
::
index_sequence
<
N
...
>
;
template
<
std
::
size_t
N
>
using
make_index_sequence
=
std
::
make_index_sequence
<
N
>
;
#else
template
<
typename
T
,
T
...
N
>
struct
integer_sequence
{
typedef
T
value_type
;
template
<
typename
T
,
T
...
N
>
struct
integer_sequence
{
using
value_type
=
T
;
static
FMT_CONSTEXPR
std
::
size_t
size
()
{
return
sizeof
...(
N
);
}
static
FMT_CONSTEXPR
std
::
size_t
size
()
{
return
sizeof
...(
N
);
}
};
template
<
std
::
size_t
...
N
>
...
...
@@ -151,7 +142,7 @@ using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif
template
<
class
Tuple
,
class
F
,
size_t
...
Is
>
void
for_each
(
index_sequence
<
Is
...
>
,
Tuple
&&
tup
,
F
&&
f
)
FMT_NOEXCEPT
{
void
for_each
(
index_sequence
<
Is
...
>
,
Tuple
&&
tup
,
F
&&
f
)
FMT_NOEXCEPT
{
using
std
::
get
;
// using free function get<I>(T) now.
const
int
_
[]
=
{
0
,
((
void
)
f
(
get
<
Is
>
(
tup
)),
0
)...};
...
...
@@ -159,26 +150,25 @@ void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
}
template
<
class
T
>
FMT_CONSTEXPR
make_index_sequence
<
std
::
tuple_size
<
T
>::
value
>
get_indexes
(
T
const
&
)
{
return
{};
}
FMT_CONSTEXPR
make_index_sequence
<
std
::
tuple_size
<
T
>::
value
>
get_indexes
(
T
const
&
)
{
return
{};
}
template
<
class
Tuple
,
class
F
>
void
for_each
(
Tuple
&&
tup
,
F
&&
f
)
{
template
<
class
Tuple
,
class
F
>
void
for_each
(
Tuple
&&
tup
,
F
&&
f
)
{
const
auto
indexes
=
get_indexes
(
tup
);
for_each
(
indexes
,
std
::
forward
<
Tuple
>
(
tup
),
std
::
forward
<
F
>
(
f
));
}
template
<
typename
Arg
>
FMT_CONSTEXPR
const
char
*
format_str_quoted
(
bool
add_space
,
const
Arg
&
,
typename
std
::
enable_if
<
!
is_like_std_string
<
typename
std
::
decay
<
Arg
>::
type
>::
value
>::
type
*
=
nullptr
)
{
template
<
typename
Arg
,
FMT_ENABLE_IF
(
!
is_like_std_string
<
typename
std
::
decay
<
Arg
>
::
type
>::
value
)
>
FMT_CONSTEXPR
const
char
*
format_str_quoted
(
bool
add_space
,
const
Arg
&
)
{
return
add_space
?
" {}"
:
"{}"
;
}
template
<
typename
Arg
>
FMT_CONSTEXPR
const
char
*
format_str_quoted
(
bool
add_space
,
const
Arg
&
,
typename
std
::
enable_if
<
is_like_std_string
<
typename
std
::
decay
<
Arg
>::
type
>::
value
>::
type
*
=
nullptr
)
{
template
<
typename
Arg
,
FMT_ENABLE_IF
(
is_like_std_string
<
typename
std
::
decay
<
Arg
>
::
type
>::
value
)
>
FMT_CONSTEXPR
const
char
*
format_str_quoted
(
bool
add_space
,
const
Arg
&
)
{
return
add_space
?
"
\"
{}
\"
"
:
"
\"
{}
\"
"
;
}
...
...
@@ -198,28 +188,24 @@ FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
}
// namespace internal
template
<
typename
T
>
struct
is_tuple_like
{
template
<
typename
T
>
struct
is_tuple_like
{
static
FMT_CONSTEXPR_DECL
const
bool
value
=
internal
::
is_tuple_like_
<
T
>::
value
&&
!
internal
::
is_range_
<
T
>::
value
;
};
template
<
typename
TupleT
,
typename
Char
>
struct
formatter
<
TupleT
,
Char
,
typename
std
::
enable_if
<
fmt
::
is_tuple_like
<
TupleT
>::
value
>::
type
>
{
private:
struct
formatter
<
TupleT
,
Char
,
enable_if_t
<
fmt
::
is_tuple_like
<
TupleT
>::
value
>>
{
private:
// C++11 generic lambda for format()
template
<
typename
FormatContext
>
struct
format_each
{
template
<
typename
T
>
void
operator
()(
const
T
&
v
)
{
template
<
typename
FormatContext
>
struct
format_each
{
template
<
typename
T
>
void
operator
()(
const
T
&
v
)
{
if
(
i
>
0
)
{
if
(
formatting
.
add_prepostfix_space
)
{
*
out
++
=
' '
;
}
internal
::
copy
(
formatting
.
delimiter
,
out
);
out
=
internal
::
copy
(
formatting
.
delimiter
,
out
);
}
format_to
(
out
,
out
=
format_to
(
out
,
internal
::
format_str_quoted
(
(
formatting
.
add_delimiter_spaces
&&
i
>
0
),
v
),
v
);
...
...
@@ -228,19 +214,20 @@ private:
formatting_tuple
<
Char
>&
formatting
;
std
::
size_t
&
i
;
typename
std
::
add_lvalue_reference
<
decltype
(
std
::
declval
<
FormatContext
>
().
out
())
>::
type
out
;
typename
std
::
add_lvalue_reference
<
decltype
(
std
::
declval
<
FormatContext
>
().
out
())
>::
type
out
;
};
public:
public:
formatting_tuple
<
Char
>
formatting
;
template
<
typename
ParseContext
>
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
return
formatting
.
parse
(
ctx
);
}
template
<
typename
FormatContext
=
format_context
>
auto
format
(
const
TupleT
&
values
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
format
(
const
TupleT
&
values
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
auto
out
=
ctx
.
out
();
std
::
size_t
i
=
0
;
internal
::
copy
(
formatting
.
prefix
,
out
);
...
...
@@ -255,54 +242,47 @@ public:
}
};
template
<
typename
T
>
struct
is_range
{
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
;
internal
::
is_range_
<
T
>::
value
&&
!
internal
::
is_like_std_string
<
T
>::
value
&&
!
std
::
is_convertible
<
T
,
std
::
basic_string
<
Char
>>::
value
;
};
template
<
typename
RangeT
,
typename
Char
>
struct
formatter
<
RangeT
,
Char
,
typename
std
::
enable_if
<
fmt
::
is_range
<
RangeT
>::
value
>::
type
>
{
enable_if_t
<
fmt
::
is_range
<
RangeT
,
Char
>::
value
>>
{
formatting_range
<
Char
>
formatting
;
template
<
typename
ParseContext
>
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
return
formatting
.
parse
(
ctx
);
}
template
<
typename
FormatContext
>
typename
FormatContext
::
iterator
format
(
const
RangeT
&
values
,
FormatContext
&
ctx
)
{
auto
out
=
ctx
.
out
();
internal
::
copy
(
formatting
.
prefix
,
out
);
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
)
{
if
(
i
>
0
)
{
if
(
formatting
.
add_prepostfix_space
)
{
*
out
++
=
' '
;
}
internal
::
copy
(
formatting
.
delimiter
,
out
);
if
(
formatting
.
add_prepostfix_space
)
*
out
++
=
' '
;
out
=
internal
::
copy
(
formatting
.
delimiter
,
out
);
}
format_to
(
out
,
out
=
format_to
(
out
,
internal
::
format_str_quoted
(
(
formatting
.
add_delimiter_spaces
&&
i
>
0
),
*
it
),
*
it
);
if
(
++
i
>
formatting
.
range_length_limit
)
{
format_to
(
out
,
" ... <other elements>"
);
out
=
format_to
(
out
,
" ... <other elements>"
);
break
;
}
}
if
(
formatting
.
add_prepostfix_space
)
{
*
out
++
=
' '
;
}
internal
::
copy
(
formatting
.
postfix
,
out
);
return
ctx
.
out
();
if
(
formatting
.
add_prepostfix_space
)
*
out
++
=
' '
;
return
internal
::
copy
(
formatting
.
postfix
,
out
);
}
};
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_
include/spdlog/fmt/bundled/safe-duration-cast.h
0 → 100644
View file @
e149433a
/*
* For conversion between std::chrono::durations without undefined
* behaviour or erroneous results.
* This is a stripped down version of duration_cast, for inclusion in fmt.
* See https://github.com/pauldreik/safe_duration_cast
*
* Copyright Paul Dreik 2019
*
* This file is licensed under the fmt license, see format.h
*/
#include <chrono>
#include <cmath>
#include <limits>
#include <type_traits>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace
safe_duration_cast
{
template
<
typename
To
,
typename
From
,
FMT_ENABLE_IF
(
!
std
::
is_same
<
From
,
To
>
::
value
&&
std
::
numeric_limits
<
From
>::
is_signed
==
std
::
numeric_limits
<
To
>::
is_signed
)
>
FMT_CONSTEXPR
To
lossless_integral_conversion
(
const
From
from
,
int
&
ec
)
{
ec
=
0
;
using
F
=
std
::
numeric_limits
<
From
>
;
using
T
=
std
::
numeric_limits
<
To
>
;
static_assert
(
F
::
is_integer
,
"From must be integral"
);
static_assert
(
T
::
is_integer
,
"To must be integral"
);
// A and B are both signed, or both unsigned.
if
(
F
::
digits
<=
T
::
digits
)
{
// 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
())
{
// outside range.
ec
=
1
;
return
{};
}
}
return
static_cast
<
To
>
(
from
);
}
/**
* converts From to To, without loss. If the dynamic value of from
* can't be converted to To without loss, ec is set.
*/
template
<
typename
To
,
typename
From
,
FMT_ENABLE_IF
(
!
std
::
is_same
<
From
,
To
>
::
value
&&
std
::
numeric_limits
<
From
>::
is_signed
!=
std
::
numeric_limits
<
To
>::
is_signed
)
>
FMT_CONSTEXPR
To
lossless_integral_conversion
(
const
From
from
,
int
&
ec
)
{
ec
=
0
;
using
F
=
std
::
numeric_limits
<
From
>
;
using
T
=
std
::
numeric_limits
<
To
>
;
static_assert
(
F
::
is_integer
,
"From must be integral"
);
static_assert
(
T
::
is_integer
,
"To must be integral"
);
if
(
F
::
is_signed
&&
!
T
::
is_signed
)
{
// From may be negative, not allowed!
if
(
from
<
0
)
{
ec
=
1
;
return
{};
}
// From is positive. Can it always fit in To?
if
(
F
::
digits
<=
T
::
digits
)
{
// 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
()))
{
ec
=
1
;
return
{};
}
}
}
if
(
!
F
::
is_signed
&&
T
::
is_signed
)
{
// can from be held in To?
if
(
F
::
digits
<
T
::
digits
)
{
// 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
()))
{
// outside range.
ec
=
1
;
return
{};
}
}
}
// reaching here means all is ok for lossless conversion.
return
static_cast
<
To
>
(
from
);
}
// function
template
<
typename
To
,
typename
From
,
FMT_ENABLE_IF
(
std
::
is_same
<
From
,
To
>
::
value
)
>
FMT_CONSTEXPR
To
lossless_integral_conversion
(
const
From
from
,
int
&
ec
)
{
ec
=
0
;
return
from
;
}
// function
// clang-format off
/**
* converts From to To if possible, otherwise ec is set.
*
* input | output
* ---------------------------------|---------------
* NaN | NaN
* Inf | Inf
* normal, fits in output | converted (possibly lossy)
* normal, does not fit in output | ec is set
* subnormal | best effort
* -Inf | -Inf
*/
// clang-format on
template
<
typename
To
,
typename
From
,
FMT_ENABLE_IF
(
!
std
::
is_same
<
From
,
To
>
::
value
)
>
FMT_CONSTEXPR
To
safe_float_conversion
(
const
From
from
,
int
&
ec
)
{
ec
=
0
;
using
T
=
std
::
numeric_limits
<
To
>
;
static_assert
(
std
::
is_floating_point
<
From
>::
value
,
"From must be floating"
);
static_assert
(
std
::
is_floating_point
<
To
>::
value
,
"To must be floating"
);
// catch the only happy case
if
(
std
::
isfinite
(
from
))
{
if
(
from
>=
T
::
lowest
()
&&
from
<=
T
::
max
())
{
return
static_cast
<
To
>
(
from
);
}
// not within range.
ec
=
1
;
return
{};
}
// nan and inf will be preserved
return
static_cast
<
To
>
(
from
);
}
// function
template
<
typename
To
,
typename
From
,
FMT_ENABLE_IF
(
std
::
is_same
<
From
,
To
>
::
value
)
>
FMT_CONSTEXPR
To
safe_float_conversion
(
const
From
from
,
int
&
ec
)
{
ec
=
0
;
static_assert
(
std
::
is_floating_point
<
From
>::
value
,
"From must be floating"
);
return
from
;
}
/**
* safe duration cast between integral durations
*/
template
<
typename
To
,
typename
FromRep
,
typename
FromPeriod
,
FMT_ENABLE_IF
(
std
::
is_integral
<
FromRep
>
::
value
),
FMT_ENABLE_IF
(
std
::
is_integral
<
typename
To
::
rep
>::
value
)
>
To
safe_duration_cast
(
std
::
chrono
::
duration
<
FromRep
,
FromPeriod
>
from
,
int
&
ec
)
{
using
From
=
std
::
chrono
::
duration
<
FromRep
,
FromPeriod
>
;
ec
=
0
;
// the basic idea is that we need to convert from count() in the from type
// to count() in the To type, by multiplying it with this:
using
Factor
=
std
::
ratio_divide
<
typename
From
::
period
,
typename
To
::
period
>
;
static_assert
(
Factor
::
num
>
0
,
"num must be positive"
);
static_assert
(
Factor
::
den
>
0
,
"den must be positive"
);
// the conversion is like this: multiply from.count() with Factor::num
// /Factor::den and convert it to To::rep, all this without
// overflow/underflow. let's start by finding a suitable type that can hold
// both To, From and Factor::num
using
IntermediateRep
=
typename
std
::
common_type
<
typename
From
::
rep
,
typename
To
::
rep
,
decltype
(
Factor
::
num
)
>::
type
;
// safe conversion to IntermediateRep
IntermediateRep
count
=
lossless_integral_conversion
<
IntermediateRep
>
(
from
.
count
(),
ec
);
if
(
ec
)
{
return
{};
}
// multiply with Factor::num without overflow or underflow
if
(
Factor
::
num
!=
1
)
{
constexpr
auto
max1
=
std
::
numeric_limits
<
IntermediateRep
>::
max
()
/
Factor
::
num
;
if
(
count
>
max1
)
{
ec
=
1
;
return
{};
}
constexpr
auto
min1
=
std
::
numeric_limits
<
IntermediateRep
>::
min
()
/
Factor
::
num
;
if
(
count
<
min1
)
{
ec
=
1
;
return
{};
}
count
*=
Factor
::
num
;
}
// this can't go wrong, right? den>0 is checked earlier.
if
(
Factor
::
den
!=
1
)
{
count
/=
Factor
::
den
;
}
// convert to the to type, safely
using
ToRep
=
typename
To
::
rep
;
const
ToRep
tocount
=
lossless_integral_conversion
<
ToRep
>
(
count
,
ec
);
if
(
ec
)
{
return
{};
}
return
To
{
tocount
};
}
/**
* safe duration_cast between floating point durations
*/
template
<
typename
To
,
typename
FromRep
,
typename
FromPeriod
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
FromRep
>
::
value
),
FMT_ENABLE_IF
(
std
::
is_floating_point
<
typename
To
::
rep
>::
value
)
>
To
safe_duration_cast
(
std
::
chrono
::
duration
<
FromRep
,
FromPeriod
>
from
,
int
&
ec
)
{
using
From
=
std
::
chrono
::
duration
<
FromRep
,
FromPeriod
>
;
ec
=
0
;
if
(
std
::
isnan
(
from
.
count
()))
{
// nan in, gives nan out. easy.
return
To
{
std
::
numeric_limits
<
typename
To
::
rep
>::
quiet_NaN
()};
}
// maybe we should also check if from is denormal, and decide what to do about
// it.
// +-inf should be preserved.
if
(
std
::
isinf
(
from
.
count
()))
{
return
To
{
from
.
count
()};
}
// the basic idea is that we need to convert from count() in the from type
// to count() in the To type, by multiplying it with this:
using
Factor
=
std
::
ratio_divide
<
typename
From
::
period
,
typename
To
::
period
>
;
static_assert
(
Factor
::
num
>
0
,
"num must be positive"
);
static_assert
(
Factor
::
den
>
0
,
"den must be positive"
);
// the conversion is like this: multiply from.count() with Factor::num
// /Factor::den and convert it to To::rep, all this without
// overflow/underflow. let's start by finding a suitable type that can hold
// both To, From and Factor::num
using
IntermediateRep
=
typename
std
::
common_type
<
typename
From
::
rep
,
typename
To
::
rep
,
decltype
(
Factor
::
num
)
>::
type
;
// force conversion of From::rep -> IntermediateRep to be safe,
// even if it will never happen be narrowing in this context.
IntermediateRep
count
=
safe_float_conversion
<
IntermediateRep
>
(
from
.
count
(),
ec
);
if
(
ec
)
{
return
{};
}
// multiply with Factor::num without overflow or underflow
if
(
Factor
::
num
!=
1
)
{
constexpr
auto
max1
=
std
::
numeric_limits
<
IntermediateRep
>::
max
()
/
static_cast
<
IntermediateRep
>
(
Factor
::
num
);
if
(
count
>
max1
)
{
ec
=
1
;
return
{};
}
constexpr
auto
min1
=
std
::
numeric_limits
<
IntermediateRep
>::
lowest
()
/
static_cast
<
IntermediateRep
>
(
Factor
::
num
);
if
(
count
<
min1
)
{
ec
=
1
;
return
{};
}
count
*=
static_cast
<
IntermediateRep
>
(
Factor
::
num
);
}
// this can't go wrong, right? den>0 is checked earlier.
if
(
Factor
::
den
!=
1
)
{
using
common_t
=
typename
std
::
common_type
<
IntermediateRep
,
intmax_t
>::
type
;
count
/=
static_cast
<
common_t
>
(
Factor
::
den
);
}
// convert to the to type, safely
using
ToRep
=
typename
To
::
rep
;
const
ToRep
tocount
=
safe_float_conversion
<
ToRep
>
(
count
,
ec
);
if
(
ec
)
{
return
{};
}
return
To
{
tocount
};
}
}
// namespace safe_duration_cast
FMT_END_NAMESPACE
include/spdlog/fmt/bundled/time.h
deleted
100644 → 0
View file @
65d02e49
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
#include <locale>
FMT_BEGIN_NAMESPACE
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
namespace
internal
{
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 internal
// Thread-safe replacement for std::localtime
inline
std
::
tm
localtime
(
std
::
time_t
time
)
{
struct
dispatcher
{
std
::
time_t
time_
;
std
::
tm
tm_
;
dispatcher
(
std
::
time_t
t
)
:
time_
(
t
)
{}
bool
run
()
{
using
namespace
fmt
::
internal
;
return
handle
(
localtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
FMT_NULL
;
}
bool
handle
(
internal
::
null
<>
)
{
using
namespace
fmt
::
internal
;
return
fallback
(
localtime_s
(
&
tm_
,
&
time_
));
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
#if !FMT_MSC_VER
bool
fallback
(
internal
::
null
<>
)
{
using
namespace
fmt
::
internal
;
std
::
tm
*
tm
=
std
::
localtime
(
&
time_
);
if
(
tm
)
tm_
=
*
tm
;
return
tm
!=
FMT_NULL
;
}
#endif
};
dispatcher
lt
(
time
);
// Too big time values may be unsupported.
if
(
!
lt
.
run
())
FMT_THROW
(
format_error
(
"time_t value out of range"
));
return
lt
.
tm_
;
}
// Thread-safe replacement for std::gmtime
inline
std
::
tm
gmtime
(
std
::
time_t
time
)
{
struct
dispatcher
{
std
::
time_t
time_
;
std
::
tm
tm_
;
dispatcher
(
std
::
time_t
t
)
:
time_
(
t
)
{}
bool
run
()
{
using
namespace
fmt
::
internal
;
return
handle
(
gmtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
FMT_NULL
;
}
bool
handle
(
internal
::
null
<>
)
{
using
namespace
fmt
::
internal
;
return
fallback
(
gmtime_s
(
&
tm_
,
&
time_
));
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
#if !FMT_MSC_VER
bool
fallback
(
internal
::
null
<>
)
{
std
::
tm
*
tm
=
std
::
gmtime
(
&
time_
);
if
(
tm
)
tm_
=
*
tm
;
return
tm
!=
FMT_NULL
;
}
#endif
};
dispatcher
gt
(
time
);
// Too big time values may be unsupported.
if
(
!
gt
.
run
())
FMT_THROW
(
format_error
(
"time_t value out of range"
));
return
gt
.
tm_
;
}
namespace
internal
{
inline
std
::
size_t
strftime
(
char
*
str
,
std
::
size_t
count
,
const
char
*
format
,
const
std
::
tm
*
time
)
{
return
std
::
strftime
(
str
,
count
,
format
,
time
);
}
inline
std
::
size_t
strftime
(
wchar_t
*
str
,
std
::
size_t
count
,
const
wchar_t
*
format
,
const
std
::
tm
*
time
)
{
return
std
::
wcsftime
(
str
,
count
,
format
,
time
);
}
}
template
<
typename
Char
>
struct
formatter
<
std
::
tm
,
Char
>
{
template
<
typename
ParseContext
>
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
auto
it
=
ctx
.
begin
();
if
(
it
!=
ctx
.
end
()
&&
*
it
==
':'
)
++
it
;
auto
end
=
it
;
while
(
end
!=
ctx
.
end
()
&&
*
end
!=
'}'
)
++
end
;
tm_format
.
reserve
(
internal
::
to_unsigned
(
end
-
it
+
1
));
tm_format
.
append
(
it
,
end
);
tm_format
.
push_back
(
'\0'
);
return
end
;
}
template
<
typename
FormatContext
>
auto
format
(
const
std
::
tm
&
tm
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
basic_memory_buffer
<
Char
>
buf
;
std
::
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
);
if
(
count
!=
0
)
{
buf
.
resize
(
start
+
count
);
break
;
}
if
(
size
>=
tm_format
.
size
()
*
256
)
{
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break
;
}
const
std
::
size_t
MIN_GROWTH
=
10
;
buf
.
reserve
(
buf
.
capacity
()
+
(
size
>
MIN_GROWTH
?
size
:
MIN_GROWTH
));
}
return
std
::
copy
(
buf
.
begin
(),
buf
.
end
(),
ctx
.
out
());
}
basic_memory_buffer
<
Char
>
tm_format
;
};
FMT_END_NAMESPACE
#endif // FMT_TIME_H_
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