Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
S
spdlog
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
spdlog
Commits
1c13f5d7
Commit
1c13f5d7
authored
Jul 08, 2015
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated cppformat to fix issue #110
parent
83d47aa6
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1299 additions
and
776 deletions
+1299
-776
format.cc
include/spdlog/details/format.cc
+411
-265
format.h
include/spdlog/details/format.h
+888
-511
No files found.
include/spdlog/details/format.cc
View file @
1c13f5d7
/*
Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
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.
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.
*/
Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
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.
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.
*/
#include "format.h"
...
...
@@ -35,11 +35,18 @@
#include <cmath>
#include <cstdarg>
#ifdef _WIN32
# ifdef __MINGW32__
#if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
# endif
#endif
#if FMT_USE_WINDOWS_H
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
using
fmt
::
internal
::
Arg
;
...
...
@@ -88,13 +95,14 @@ using fmt::internal::Arg;
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
static
inline
fmt
::
internal
::
N
one
<>
strerror_r
(
int
,
char
*
,
...)
{
return
fmt
::
internal
::
None
<>
();
static
inline
fmt
::
internal
::
N
ull
<>
strerror_r
(
int
,
char
*
,
...)
{
return
fmt
::
internal
::
Null
<>
();
}
static
inline
fmt
::
internal
::
N
one
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
fmt
::
internal
::
None
<>
();
static
inline
fmt
::
internal
::
N
ull
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
fmt
::
internal
::
Null
<>
();
}
namespace
fmt
{
namespace
{
#ifndef _MSC_VER
...
...
@@ -125,6 +133,9 @@ struct IntChecker {
unsigned
max
=
INT_MAX
;
return
value
<=
max
;
}
static
bool
fits_in_int
(
bool
)
{
return
true
;
}
};
template
<>
...
...
@@ -137,7 +148,7 @@ struct IntChecker<true> {
const
char
RESET_COLOR
[]
=
"
\x1b
[0m"
;
typedef
void
(
*
FormatFunc
)(
fmt
::
Writer
&
,
int
,
fmt
::
StringRef
);
typedef
void
(
*
FormatFunc
)(
fmt
::
Writer
&
,
int
,
fmt
::
StringRef
);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
...
...
@@ -149,8 +160,8 @@ typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// 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
{
assert
(
buffer
!=
0
&&
buffer_size
!=
0
);
int
error_code
,
char
*&
buffer
,
std
::
size_t
buffer_size
)
FMT_NOEXCEPT
{
FMT_ASSERT
(
buffer
!=
0
&&
buffer_size
!=
0
,
"invalid buffer"
);
class
StrError
{
private
:
...
...
@@ -177,7 +188,7 @@ int safe_strerror(
}
// Handle the case when strerror_r is not available.
int
handle
(
fmt
::
internal
::
None
<>
)
{
int
handle
(
fmt
::
internal
::
Null
<>
)
{
return
fallback
(
strerror_s
(
buffer_
,
buffer_size_
,
error_code_
));
}
...
...
@@ -189,7 +200,7 @@ int safe_strerror(
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int
fallback
(
fmt
::
internal
::
None
<>
)
{
int
fallback
(
fmt
::
internal
::
Null
<>
)
{
errno
=
0
;
buffer_
=
strerror
(
error_code_
);
return
errno
;
...
...
@@ -199,13 +210,16 @@ int safe_strerror(
StrError
(
int
error_code
,
char
*&
buffer
,
std
::
size_t
buffer_size
)
:
error_code_
(
error_code
),
buffer_
(
buffer
),
buffer_size_
(
buffer_size
)
{}
int
run
()
{
return
handle
(
strerror_r
(
error_code_
,
buffer_
,
buffer_size_
));
}
int
run
()
{
strerror_r
(
0
,
0
,
""
);
// Suppress a warning about unused strerror_r.
return
handle
(
strerror_r
(
error_code_
,
buffer_
,
buffer_size_
));
}
};
return
StrError
(
error_code
,
buffer
,
buffer_size
).
run
();
}
void
format_error_code
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
...
...
@@ -223,7 +237,7 @@ void format_error_code(fmt::Writer &out, int error_code,
}
void
report_error
(
FormatFunc
func
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
fmt
::
MemoryWriter
full_message
;
func
(
full_message
,
error_code
,
message
);
// Use Writer::data instead of Writer::c_str to avoid potential memory
...
...
@@ -234,9 +248,11 @@ void report_error(FormatFunc func,
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class
IsZeroInt
:
public
fmt
::
internal
::
ArgVisitor
<
IsZeroInt
,
bool
>
{
public
:
public
:
template
<
typename
T
>
bool
visit_any_int
(
T
value
)
{
return
value
==
0
;
}
bool
visit_any_int
(
T
value
)
{
return
value
==
0
;
}
};
// Parses an unsigned integer advancing s to the end of the parsed input.
...
...
@@ -259,6 +275,11 @@ int parse_nonnegative_int(const Char *&s) {
return
value
;
}
template
<
typename
Char
>
inline
bool
is_name_start
(
Char
c
)
{
return
(
'a'
<=
c
&&
c
<=
'z'
)
||
(
'A'
<=
c
&&
c
<=
'Z'
)
||
'_'
==
c
;
}
inline
void
require_numeric_argument
(
const
Arg
&
arg
,
char
spec
)
{
if
(
arg
.
type
>
Arg
::
LAST_NUMERIC_TYPE
)
{
std
::
string
message
=
...
...
@@ -281,12 +302,12 @@ void check_sign(const Char *&s, const Arg &arg) {
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
class
WidthHandler
:
public
fmt
::
internal
::
ArgVisitor
<
WidthHandler
,
unsigned
>
{
private
:
private
:
fmt
::
FormatSpec
&
spec_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
WidthHandler
);
public
:
public
:
explicit
WidthHandler
(
fmt
::
FormatSpec
&
spec
)
:
spec_
(
spec
)
{}
void
report_unhandled_arg
()
{
...
...
@@ -309,7 +330,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
class
PrecisionHandler
:
public
fmt
::
internal
::
ArgVisitor
<
PrecisionHandler
,
int
>
{
public
:
public
:
void
report_unhandled_arg
()
{
FMT_THROW
(
fmt
::
FormatError
(
"precision is not integer"
));
}
...
...
@@ -325,13 +346,13 @@ class PrecisionHandler :
// Converts an integer argument to an integral type T for printf.
template
<
typename
T
>
class
ArgConverter
:
public
fmt
::
internal
::
ArgVisitor
<
ArgConverter
<
T
>
,
void
>
{
private
:
private
:
fmt
::
internal
::
Arg
&
arg_
;
wchar_t
type_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgConverter
);
public
:
public
:
ArgConverter
(
fmt
::
internal
::
Arg
&
arg
,
wchar_t
type
)
:
arg_
(
arg
),
type_
(
type
)
{}
...
...
@@ -344,17 +365,20 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
if
(
is_signed
)
{
arg_
.
type
=
Arg
::
INT
;
arg_
.
int_value
=
static_cast
<
int
>
(
static_cast
<
T
>
(
value
));
}
else
{
}
else
{
arg_
.
type
=
Arg
::
UINT
;
arg_
.
uint_value
=
static_cast
<
unsigned
>
(
static_cast
<
typename
fmt
::
internal
::
MakeUnsigned
<
T
>::
Type
>
(
value
));
}
}
else
{
}
else
{
if
(
is_signed
)
{
arg_
.
type
=
Arg
::
LONG_LONG
;
arg_
.
long_long_value
=
static_cast
<
typename
fmt
::
internal
::
MakeUnsigned
<
U
>::
Type
>
(
value
);
}
else
{
}
else
{
arg_
.
type
=
Arg
::
ULONG_LONG
;
arg_
.
ulong_long_value
=
static_cast
<
typename
fmt
::
internal
::
MakeUnsigned
<
U
>::
Type
>
(
value
);
...
...
@@ -365,12 +389,12 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
// Converts an integer argument to char for printf.
class
CharConverter
:
public
fmt
::
internal
::
ArgVisitor
<
CharConverter
,
void
>
{
private
:
private
:
fmt
::
internal
::
Arg
&
arg_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
CharConverter
);
public
:
public
:
explicit
CharConverter
(
fmt
::
internal
::
Arg
&
arg
)
:
arg_
(
arg
)
{}
template
<
typename
T
>
...
...
@@ -379,24 +403,152 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
arg_
.
int_value
=
static_cast
<
char
>
(
value
);
}
};
}
// namespace
namespace
internal
{
template
<
typename
Impl
,
typename
Char
>
class
BasicArgFormatter
:
public
ArgVisitor
<
Impl
,
void
>
{
private
:
BasicWriter
<
Char
>
&
writer_
;
FormatSpec
&
spec_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
BasicArgFormatter
);
protected
:
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
}
const
FormatSpec
&
spec
()
const
{
return
spec_
;
}
public
:
BasicArgFormatter
(
BasicWriter
<
Char
>
&
w
,
FormatSpec
&
s
)
:
writer_
(
w
),
spec_
(
s
)
{}
template
<
typename
T
>
void
visit_any_int
(
T
value
)
{
writer_
.
write_int
(
value
,
spec_
);
}
template
<
typename
T
>
void
visit_any_double
(
T
value
)
{
writer_
.
write_double
(
value
,
spec_
);
}
void
visit_bool
(
bool
value
)
{
if
(
spec_
.
type_
)
{
writer_
.
write_int
(
value
,
spec_
);
return
;
}
const
char
*
str_value
=
value
?
"true"
:
"false"
;
Arg
::
StringValue
<
char
>
str
=
{
str_value
,
strlen
(
str_value
)
};
writer_
.
write_str
(
str
,
spec_
);
}
// This function template is used to prevent compile errors when handling
// incompatible string arguments, e.g. handling a wide string in a narrow
// string formatter.
void
visit_char
(
int
value
)
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'c'
)
{
spec_
.
flags_
|=
CHAR_FLAG
;
writer_
.
write_int
(
value
,
spec_
);
return
;
}
if
(
spec_
.
align_
==
ALIGN_NUMERIC
||
spec_
.
flags_
!=
0
)
FMT_THROW
(
FormatError
(
"invalid format specifier for char"
));
typedef
typename
BasicWriter
<
Char
>::
CharPtr
CharPtr
;
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec_
.
fill
());
CharPtr
out
=
CharPtr
();
if
(
spec_
.
width_
>
1
)
{
out
=
writer_
.
grow_buffer
(
spec_
.
width_
);
if
(
spec_
.
align_
==
ALIGN_RIGHT
)
{
std
::
fill_n
(
out
,
spec_
.
width_
-
1
,
fill
);
out
+=
spec_
.
width_
-
1
;
}
else
if
(
spec_
.
align_
==
ALIGN_CENTER
)
{
out
=
writer_
.
fill_padding
(
out
,
spec_
.
width_
,
1
,
fill
);
}
else
{
std
::
fill_n
(
out
+
1
,
spec_
.
width_
-
1
,
fill
);
}
}
else
{
out
=
writer_
.
grow_buffer
(
1
);
}
*
out
=
internal
::
CharTraits
<
Char
>::
cast
(
value
);
}
void
visit_string
(
Arg
::
StringValue
<
char
>
value
)
{
writer_
.
write_str
(
value
,
spec_
);
}
using
ArgVisitor
<
Impl
,
void
>::
visit_wstring
;
void
visit_wstring
(
Arg
::
StringValue
<
Char
>
value
)
{
writer_
.
write_str
(
value
,
spec_
);
}
void
visit_pointer
(
const
void
*
value
)
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'p'
)
report_unknown_type
(
spec_
.
type_
,
"pointer"
);
spec_
.
flags_
=
HASH_FLAG
;
spec_
.
type_
=
'x'
;
writer_
.
write_int
(
reinterpret_cast
<
uintptr_t
>
(
value
),
spec_
);
}
};
// An argument formatter.
template
<
typename
Char
>
Arg
::
StringValue
<
Char
>
ignore_incompatible_str
(
Arg
::
StringValue
<
wchar_t
>
);
class
ArgFormatter
:
public
BasicArgFormatter
<
ArgFormatter
<
Char
>
,
Char
>
{
private
:
BasicFormatter
<
Char
>
&
formatter_
;
const
Char
*
format_
;
template
<>
inline
Arg
::
StringValue
<
char
>
ignore_incompatible_str
(
Arg
::
StringValue
<
wchar_t
>
)
{
return
Arg
::
StringValue
<
char
>
();
}
public
:
ArgFormatter
(
BasicFormatter
<
Char
>
&
f
,
FormatSpec
&
s
,
const
Char
*
fmt
)
:
BasicArgFormatter
<
ArgFormatter
<
Char
>
,
Char
>
(
f
.
writer
(),
s
),
formatter_
(
f
),
format_
(
fmt
)
{}
template
<>
inline
Arg
::
StringValue
<
wchar_t
>
ignore_incompatible_str
(
Arg
::
StringValue
<
wchar_t
>
s
)
{
return
s
;
}
}
// namespace
void
visit_custom
(
Arg
::
CustomValue
c
)
{
c
.
format
(
&
formatter_
,
c
.
value
,
&
format_
);
}
};
template
<
typename
Char
>
class
PrintfArgFormatter
:
public
BasicArgFormatter
<
PrintfArgFormatter
<
Char
>
,
Char
>
{
public
:
PrintfArgFormatter
(
BasicWriter
<
Char
>
&
w
,
FormatSpec
&
s
)
:
BasicArgFormatter
<
PrintfArgFormatter
<
Char
>
,
Char
>
(
w
,
s
)
{}
void
visit_char
(
int
value
)
{
const
FormatSpec
&
spec
=
this
->
spec
();
BasicWriter
<
Char
>
&
writer
=
this
->
writer
();
if
(
spec
.
type_
&&
spec
.
type_
!=
'c'
)
writer
.
write_int
(
value
,
spec
);
typedef
typename
BasicWriter
<
Char
>::
CharPtr
CharPtr
;
CharPtr
out
=
CharPtr
();
if
(
spec
.
width_
>
1
)
{
Char
fill
=
' '
;
out
=
writer
.
grow_buffer
(
spec
.
width_
);
if
(
spec
.
align_
!=
ALIGN_LEFT
)
{
std
::
fill_n
(
out
,
spec
.
width_
-
1
,
fill
);
out
+=
spec
.
width_
-
1
;
}
else
{
std
::
fill_n
(
out
+
1
,
spec
.
width_
-
1
,
fill
);
}
}
else
{
out
=
writer
.
grow_buffer
(
1
);
}
*
out
=
static_cast
<
Char
>
(
value
);
}
};
}
// namespace internal
}
// namespace fmt
FMT_FUNC
void
fmt
::
SystemError
::
init
(
int
err_code
,
StringRef
format_str
,
ArgList
args
)
{
int
err_code
,
C
StringRef
format_str
,
ArgList
args
)
{
error_code_
=
err_code
;
MemoryWriter
w
;
internal
::
format_system_error
(
w
,
err_code
,
format
(
format_str
,
args
));
...
...
@@ -477,19 +629,20 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
static_cast
<
unsigned
>
(
code
),
type
)));
}
#if
def _WIN32
#if
FMT_USE_WINDOWS_H
FMT_FUNC
fmt
::
internal
::
UTF8ToUTF16
::
UTF8ToUTF16
(
fmt
::
StringRef
s
)
{
int
length
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
c_str
(),
-
1
,
0
,
0
);
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
data
(),
s
.
size
()
,
0
,
0
);
static
const
char
ERROR_MSG
[]
=
"cannot convert string from UTF-8 to UTF-16"
;
if
(
length
==
0
)
FMT_THROW
(
WindowsError
(
GetLastError
(),
ERROR_MSG
));
buffer_
.
resize
(
length
);
buffer_
.
resize
(
length
+
1
);
length
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
c_str
(),
-
1
,
&
buffer_
[
0
],
length
);
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
s
.
data
(),
s
.
size
()
,
&
buffer_
[
0
],
length
);
if
(
length
==
0
)
FMT_THROW
(
WindowsError
(
GetLastError
(),
ERROR_MSG
));
buffer_
[
length
]
=
0
;
}
FMT_FUNC
fmt
::
internal
::
UTF16ToUTF8
::
UTF16ToUTF8
(
fmt
::
WStringRef
s
)
{
...
...
@@ -500,19 +653,20 @@ FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
}
FMT_FUNC
int
fmt
::
internal
::
UTF16ToUTF8
::
convert
(
fmt
::
WStringRef
s
)
{
int
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
c_str
(),
-
1
,
0
,
0
,
0
,
0
);
int
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
data
(),
s
.
size
()
,
0
,
0
,
0
,
0
);
if
(
length
==
0
)
return
GetLastError
();
buffer_
.
resize
(
length
);
buffer_
.
resize
(
length
+
1
);
length
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
s
.
c_str
(),
-
1
,
&
buffer_
[
0
],
length
,
0
,
0
);
CP_UTF8
,
0
,
s
.
data
(),
s
.
size
()
,
&
buffer_
[
0
],
length
,
0
,
0
);
if
(
length
==
0
)
return
GetLastError
();
buffer_
[
length
]
=
0
;
return
0
;
}
FMT_FUNC
void
fmt
::
WindowsError
::
init
(
int
err_code
,
StringRef
format_str
,
ArgList
args
)
{
int
err_code
,
C
StringRef
format_str
,
ArgList
args
)
{
error_code_
=
err_code
;
MemoryWriter
w
;
internal
::
format_windows_error
(
w
,
err_code
,
format
(
format_str
,
args
));
...
...
@@ -520,44 +674,24 @@ FMT_FUNC void fmt::WindowsError::init(
base
=
std
::
runtime_error
(
w
.
str
());
}
#endif
FMT_FUNC
void
fmt
::
internal
::
format_system_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer
;
buffer
.
resize
(
INLINE_BUFFER_SIZE
);
for
(;;)
{
char
*
system_message
=
&
buffer
[
0
];
int
result
=
safe_strerror
(
error_code
,
system_message
,
buffer
.
size
());
if
(
result
==
0
)
{
out
<<
message
<<
": "
<<
system_message
;
return
;
}
if
(
result
!=
ERANGE
)
break
;
// Can't get error message, report error code instead.
buffer
.
resize
(
buffer
.
size
()
*
2
);
}
}
FMT_CATCH
(...)
{}
format_error_code
(
out
,
error_code
,
message
);
}
#ifdef _WIN32
FMT_FUNC
void
fmt
::
internal
::
format_windows_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
class
String
{
private
:
LPWSTR
str_
;
public
:
String
()
:
str_
()
{}
~
String
()
{
LocalFree
(
str_
);
}
LPWSTR
*
ptr
()
{
return
&
str_
;
}
~
String
()
{
LocalFree
(
str_
);
}
LPWSTR
*
ptr
()
{
return
&
str_
;
}
LPCWSTR
c_str
()
const
{
return
str_
;
}
};
FMT_TRY
{
FMT_TRY
{
String
system_message
;
if
(
FormatMessageW
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
0
,
...
...
@@ -572,81 +706,76 @@ FMT_FUNC void fmt::internal::format_windows_error(
}
FMT_CATCH
(...)
{}
format_error_code
(
out
,
error_code
,
message
);
}
#endif
// An argument formatter.
template
<
typename
Char
>
class
fmt
::
internal
::
ArgFormatter
:
public
fmt
::
internal
::
ArgVisitor
<
fmt
::
internal
::
ArgFormatter
<
Char
>
,
void
>
{
private
:
fmt
::
BasicFormatter
<
Char
>
&
formatter_
;
fmt
::
BasicWriter
<
Char
>
&
writer_
;
fmt
::
FormatSpec
&
spec_
;
const
Char
*
format_
;
#endif // FMT_USE_WINDOWS_H
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgFormatter
);
public
:
ArgFormatter
(
fmt
::
BasicFormatter
<
Char
>
&
f
,
fmt
::
FormatSpec
&
s
,
const
Char
*
fmt
)
:
formatter_
(
f
),
writer_
(
f
.
writer
()),
spec_
(
s
),
format_
(
fmt
)
{}
template
<
typename
T
>
void
visit_any_int
(
T
value
)
{
writer_
.
write_int
(
value
,
spec_
);
}
template
<
typename
T
>
void
visit_any_double
(
T
value
)
{
writer_
.
write_double
(
value
,
spec_
);
}
void
visit_char
(
int
value
)
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'c'
)
{
spec_
.
flags_
|=
CHAR_FLAG
;
writer_
.
write_int
(
value
,
spec_
);
FMT_FUNC
void
fmt
::
internal
::
format_system_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer
;
buffer
.
resize
(
INLINE_BUFFER_SIZE
);
for
(;;)
{
char
*
system_message
=
&
buffer
[
0
];
int
result
=
safe_strerror
(
error_code
,
system_message
,
buffer
.
size
());
if
(
result
==
0
)
{
out
<<
message
<<
": "
<<
system_message
;
return
;
}
if
(
spec_
.
align_
==
ALIGN_NUMERIC
||
spec_
.
flags_
!=
0
)
FMT_THROW
(
FormatError
(
"invalid format specifier for char"
));
typedef
typename
fmt
::
BasicWriter
<
Char
>::
CharPtr
CharPtr
;
Char
fill
=
static_cast
<
Char
>
(
spec_
.
fill
());
if
(
spec_
.
precision_
==
0
)
{
std
::
fill_n
(
writer_
.
grow_buffer
(
spec_
.
width_
),
spec_
.
width_
,
fill
);
return
;
if
(
result
!=
ERANGE
)
break
;
// Can't get error message, report error code instead.
buffer
.
resize
(
buffer
.
size
()
*
2
);
}
CharPtr
out
=
CharPtr
();
if
(
spec_
.
width_
>
1
)
{
out
=
writer_
.
grow_buffer
(
spec_
.
width_
);
if
(
spec_
.
align_
==
fmt
::
ALIGN_RIGHT
)
{
std
::
fill_n
(
out
,
spec_
.
width_
-
1
,
fill
);
out
+=
spec_
.
width_
-
1
;
}
else
if
(
spec_
.
align_
==
fmt
::
ALIGN_CENTER
)
{
out
=
writer_
.
fill_padding
(
out
,
spec_
.
width_
,
1
,
fill
);
}
else
{
std
::
fill_n
(
out
+
1
,
spec_
.
width_
-
1
,
fill
);
}
FMT_CATCH
(...)
{}
format_error_code
(
out
,
error_code
,
message
);
}
template
<
typename
Char
>
void
fmt
::
internal
::
ArgMap
<
Char
>::
init
(
const
ArgList
&
args
)
{
if
(
!
map_
.
empty
())
return
;
typedef
internal
::
NamedArg
<
Char
>
NamedArg
;
const
NamedArg
*
named_arg
=
0
;
bool
use_values
=
args
.
type
(
ArgList
::
MAX_PACKED_ARGS
-
1
)
==
internal
::
Arg
::
NONE
;
if
(
use_values
)
{
for
(
unsigned
i
=
0
;
/*nothing*/
;
++
i
)
{
internal
::
Arg
::
Type
arg_type
=
args
.
type
(
i
);
switch
(
arg_type
)
{
case
internal
:
:
Arg
::
NONE
:
return
;
case
internal
:
:
Arg
::
NAMED_ARG
:
named_arg
=
static_cast
<
const
NamedArg
*>
(
args
.
values_
[
i
].
pointer
);
map_
.
insert
(
Pair
(
named_arg
->
name
,
*
named_arg
));
break
;
default
:
/*nothing*/
;
}
}
else
{
out
=
writer_
.
grow_buffer
(
1
);
}
*
out
=
static_cast
<
Char
>
(
value
)
;
return
;
}
void
visit_string
(
Arg
::
StringValue
<
char
>
value
)
{
writer_
.
write_str
(
value
,
spec_
);
for
(
unsigned
i
=
0
;
i
!=
ArgList
::
MAX_PACKED_ARGS
;
++
i
)
{
internal
::
Arg
::
Type
arg_type
=
args
.
type
(
i
);
if
(
arg_type
==
internal
::
Arg
::
NAMED_ARG
)
{
named_arg
=
static_cast
<
const
NamedArg
*>
(
args
.
args_
[
i
].
pointer
);
map_
.
insert
(
Pair
(
named_arg
->
name
,
*
named_arg
));
}
void
visit_wstring
(
Arg
::
StringValue
<
wchar_t
>
value
)
{
writer_
.
write_str
(
ignore_incompatible_str
<
Char
>
(
value
),
spec_
);
}
void
visit_pointer
(
const
void
*
value
)
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'p'
)
fmt
::
internal
::
report_unknown_type
(
spec_
.
type_
,
"pointer"
);
spec_
.
flags_
=
fmt
::
HASH_FLAG
;
spec_
.
type_
=
'x'
;
writer_
.
write_int
(
reinterpret_cast
<
uintptr_t
>
(
value
),
spec_
);
for
(
unsigned
i
=
ArgList
::
MAX_PACKED_ARGS
;
/*nothing*/
;
++
i
)
{
switch
(
args
.
args_
[
i
].
type
)
{
case
internal
:
:
Arg
::
NONE
:
return
;
case
internal
:
:
Arg
::
NAMED_ARG
:
named_arg
=
static_cast
<
const
NamedArg
*>
(
args
.
args_
[
i
].
pointer
);
map_
.
insert
(
Pair
(
named_arg
->
name
,
*
named_arg
));
break
;
default
:
/*nothing*/
;
}
void
visit_custom
(
Arg
::
CustomValue
c
)
{
c
.
format
(
&
formatter_
,
c
.
value
,
&
format_
);
}
}
;
}
template
<
typename
Char
>
void
fmt
::
internal
::
FixedBuffer
<
Char
>::
grow
(
std
::
size_t
)
{
...
...
@@ -675,6 +804,19 @@ void fmt::BasicWriter<Char>::write_str(
write_str
(
str_value
,
str_size
,
spec
);
}
template
<
typename
Char
>
inline
Arg
fmt
::
BasicFormatter
<
Char
>::
get_arg
(
BasicStringRef
<
Char
>
arg_name
,
const
char
*&
error
)
{
if
(
check_no_auto_index
(
error
))
{
map_
.
init
(
args
());
const
Arg
*
arg
=
map_
.
find
(
arg_name
);
if
(
arg
)
return
*
arg
;
error
=
"argument not found"
;
}
return
Arg
();
}
template
<
typename
Char
>
inline
Arg
fmt
::
BasicFormatter
<
Char
>::
parse_arg_index
(
const
Char
*&
s
)
{
const
char
*
error
=
0
;
...
...
@@ -687,11 +829,34 @@ inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
return
arg
;
}
template
<
typename
Char
>
inline
Arg
fmt
::
BasicFormatter
<
Char
>::
parse_arg_name
(
const
Char
*&
s
)
{
assert
(
is_name_start
(
*
s
));
const
Char
*
start
=
s
;
Char
c
;
do
{
c
=
*++
s
;
}
while
(
is_name_start
(
c
)
||
(
'0'
<=
c
&&
c
<=
'9'
));
const
char
*
error
=
0
;
Arg
arg
=
get_arg
(
fmt
::
BasicStringRef
<
Char
>
(
start
,
s
-
start
),
error
);
if
(
error
)
FMT_THROW
(
fmt
::
FormatError
(
error
));
return
arg
;
}
FMT_FUNC
Arg
fmt
::
internal
::
FormatterBase
::
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
)
{
Arg
arg
=
args_
[
arg_index
];
if
(
arg
.
type
==
Arg
::
NONE
)
switch
(
arg
.
type
)
{
case
Arg
:
:
NONE
:
error
=
"argument index out of range"
;
break
;
case
Arg
:
:
NAMED_ARG
:
arg
=
*
static_cast
<
const
internal
::
Arg
*>
(
arg
.
pointer
);
default
:
/*nothing*/
;
}
return
arg
;
}
...
...
@@ -702,14 +867,19 @@ inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
return
Arg
();
}
inline
bool
fmt
::
internal
::
FormatterBase
::
check_no_auto_index
(
const
char
*&
error
)
{
if
(
next_arg_index_
>
0
)
{
error
=
"cannot switch from automatic to manual argument indexing"
;
return
false
;
}
next_arg_index_
=
-
1
;
return
true
;
}
inline
Arg
fmt
::
internal
::
FormatterBase
::
get_arg
(
unsigned
arg_index
,
const
char
*&
error
)
{
if
(
next_arg_index_
<=
0
)
{
next_arg_index_
=
-
1
;
return
do_get_arg
(
arg_index
,
error
);
}
error
=
"cannot switch from automatic to manual argument indexing"
;
return
Arg
();
return
check_no_auto_index
(
error
)
?
do_get_arg
(
arg_index
,
error
)
:
Arg
();
}
template
<
typename
Char
>
...
...
@@ -763,7 +933,8 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
if
(
*
s
==
'$'
)
{
// value is an argument index
++
s
;
arg_index
=
value
;
}
else
{
}
else
{
if
(
c
==
'0'
)
spec
.
fill_
=
'0'
;
if
(
value
!=
0
)
{
...
...
@@ -778,7 +949,8 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
// Parse width.
if
(
*
s
>=
'0'
&&
*
s
<=
'9'
)
{
spec
.
width_
=
parse_nonnegative_int
(
s
);
}
else
if
(
*
s
==
'*'
)
{
}
else
if
(
*
s
==
'*'
)
{
++
s
;
spec
.
width_
=
WidthHandler
(
spec
).
visit
(
get_arg
(
s
));
}
...
...
@@ -787,7 +959,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
template
<
typename
Char
>
void
fmt
::
internal
::
PrintfFormatter
<
Char
>::
format
(
BasicWriter
<
Char
>
&
writer
,
BasicStringRef
<
Char
>
format_str
,
BasicWriter
<
Char
>
&
writer
,
Basic
C
StringRef
<
Char
>
format_str
,
const
ArgList
&
args
)
{
const
Char
*
start
=
format_str
.
c_str
();
set_args
(
args
);
...
...
@@ -813,7 +985,8 @@ void fmt::internal::PrintfFormatter<Char>::format(
++
s
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
precision_
=
parse_nonnegative_int
(
s
);
}
else
if
(
*
s
==
'*'
)
{
}
else
if
(
*
s
==
'*'
)
{
++
s
;
spec
.
precision_
=
PrecisionHandler
().
visit
(
get_arg
(
s
));
}
...
...
@@ -868,7 +1041,8 @@ void fmt::internal::PrintfFormatter<Char>::format(
if
(
arg
.
type
<=
Arg
::
LAST_INTEGER_TYPE
)
{
// Normalize type.
switch
(
spec
.
type_
)
{
case
'i'
:
case
'u'
:
case
'i'
:
case
'u'
:
spec
.
type_
=
'd'
;
break
;
case
'c'
:
...
...
@@ -881,73 +1055,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
start
=
s
;
// Format argument.
switch
(
arg
.
type
)
{
case
Arg
:
:
INT
:
writer
.
write_int
(
arg
.
int_value
,
spec
);
break
;
case
Arg
:
:
UINT
:
writer
.
write_int
(
arg
.
uint_value
,
spec
);
break
;
case
Arg
:
:
LONG_LONG
:
writer
.
write_int
(
arg
.
long_long_value
,
spec
);
break
;
case
Arg
:
:
ULONG_LONG
:
writer
.
write_int
(
arg
.
ulong_long_value
,
spec
);
break
;
case
Arg
:
:
CHAR
:
{
if
(
spec
.
type_
&&
spec
.
type_
!=
'c'
)
writer
.
write_int
(
arg
.
int_value
,
spec
);
typedef
typename
BasicWriter
<
Char
>::
CharPtr
CharPtr
;
CharPtr
out
=
CharPtr
();
if
(
spec
.
width_
>
1
)
{
Char
fill
=
' '
;
out
=
writer
.
grow_buffer
(
spec
.
width_
);
if
(
spec
.
align_
!=
ALIGN_LEFT
)
{
std
::
fill_n
(
out
,
spec
.
width_
-
1
,
fill
);
out
+=
spec
.
width_
-
1
;
}
else
{
std
::
fill_n
(
out
+
1
,
spec
.
width_
-
1
,
fill
);
}
}
else
{
out
=
writer
.
grow_buffer
(
1
);
}
*
out
=
static_cast
<
Char
>
(
arg
.
int_value
);
break
;
}
case
Arg
:
:
DOUBLE
:
writer
.
write_double
(
arg
.
double_value
,
spec
);
break
;
case
Arg
:
:
LONG_DOUBLE
:
writer
.
write_double
(
arg
.
long_double_value
,
spec
);
break
;
case
Arg
:
:
CSTRING
:
arg
.
string
.
size
=
0
;
writer
.
write_str
(
arg
.
string
,
spec
);
break
;
case
Arg
:
:
STRING
:
writer
.
write_str
(
arg
.
string
,
spec
);
break
;
case
Arg
:
:
WSTRING
:
writer
.
write_str
(
ignore_incompatible_str
<
Char
>
(
arg
.
wstring
),
spec
);
break
;
case
Arg
:
:
POINTER
:
if
(
spec
.
type_
&&
spec
.
type_
!=
'p'
)
internal
::
report_unknown_type
(
spec
.
type_
,
"pointer"
);
spec
.
flags_
=
HASH_FLAG
;
spec
.
type_
=
'x'
;
writer
.
write_int
(
reinterpret_cast
<
uintptr_t
>
(
arg
.
pointer
),
spec
);
break
;
case
Arg
:
:
CUSTOM
:
{
if
(
spec
.
type_
)
internal
::
report_unknown_type
(
spec
.
type_
,
"object"
);
const
void
*
str_format
=
"s"
;
arg
.
custom
.
format
(
&
writer
,
arg
.
custom
.
value
,
&
str_format
);
break
;
}
default
:
assert
(
false
);
break
;
}
internal
::
PrintfArgFormatter
<
Char
>
(
writer
,
spec
).
visit
(
arg
);
}
write
(
writer
,
start
,
s
);
}
...
...
@@ -989,7 +1097,8 @@ const Char *fmt::BasicFormatter<Char>::format(
FMT_THROW
(
FormatError
(
"invalid fill character '{'"
));
s
+=
2
;
spec
.
fill_
=
c
;
}
else
++
s
;
}
else
++
s
;
if
(
spec
.
align_
==
ALIGN_NUMERIC
)
require_numeric_argument
(
arg
,
'='
);
break
;
...
...
@@ -1019,17 +1128,49 @@ const Char *fmt::BasicFormatter<Char>::format(
++
s
;
}
// Parse width and zero flag.
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
// Parse zero flag.
if
(
*
s
==
'0'
)
{
require_numeric_argument
(
arg
,
'0'
);
spec
.
align_
=
ALIGN_NUMERIC
;
spec
.
fill_
=
'0'
;
++
s
;
}
// Zero may be parsed again as a part of the width, but it is simpler
// and more efficient than checking if the next char is a digit.
// Parse width.
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
width_
=
parse_nonnegative_int
(
s
);
}
else
if
(
*
s
==
'{'
)
{
++
s
;
Arg
width_arg
=
is_name_start
(
*
s
)
?
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
if
(
*
s
++
!=
'}'
)
FMT_THROW
(
FormatError
(
"invalid format string"
));
ULongLong
value
=
0
;
switch
(
width_arg
.
type
)
{
case
Arg
:
:
INT
:
if
(
width_arg
.
int_value
<
0
)
FMT_THROW
(
FormatError
(
"negative width"
));
value
=
width_arg
.
int_value
;
break
;
case
Arg
:
:
UINT
:
value
=
width_arg
.
uint_value
;
break
;
case
Arg
:
:
LONG_LONG
:
if
(
width_arg
.
long_long_value
<
0
)
FMT_THROW
(
FormatError
(
"negative width"
));
value
=
width_arg
.
long_long_value
;
break
;
case
Arg
:
:
ULONG_LONG
:
value
=
width_arg
.
ulong_long_value
;
break
;
default
:
FMT_THROW
(
FormatError
(
"width is not integer"
));
}
if
(
value
>
INT_MAX
)
FMT_THROW
(
FormatError
(
"number is too big"
));
spec
.
width_
=
static_cast
<
int
>
(
value
);
}
// Parse precision.
if
(
*
s
==
'.'
)
{
...
...
@@ -1037,9 +1178,11 @@ const Char *fmt::BasicFormatter<Char>::format(
spec
.
precision_
=
0
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
precision_
=
parse_nonnegative_int
(
s
);
}
else
if
(
*
s
==
'{'
)
{
}
else
if
(
*
s
==
'{'
)
{
++
s
;
const
Arg
&
precision_arg
=
parse_arg_index
(
s
);
Arg
precision_arg
=
is_name_start
(
*
s
)
?
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
if
(
*
s
++
!=
'}'
)
FMT_THROW
(
FormatError
(
"invalid format string"
));
ULongLong
value
=
0
;
...
...
@@ -1066,10 +1209,11 @@ const Char *fmt::BasicFormatter<Char>::format(
if
(
value
>
INT_MAX
)
FMT_THROW
(
FormatError
(
"number is too big"
));
spec
.
precision_
=
static_cast
<
int
>
(
value
);
}
else
{
}
else
{
FMT_THROW
(
FormatError
(
"missing precision specifier"
));
}
if
(
arg
.
type
<
Arg
::
LAST_INTEGER_TYPE
||
arg
.
type
==
Arg
::
POINTER
)
{
if
(
arg
.
type
<=
Arg
::
LAST_INTEGER_TYPE
||
arg
.
type
==
Arg
::
POINTER
)
{
FMT_THROW
(
FormatError
(
fmt
::
format
(
"precision not allowed in {} format specifier"
,
arg
.
type
==
Arg
::
POINTER
?
"pointer"
:
"integer"
)));
...
...
@@ -1092,7 +1236,7 @@ const Char *fmt::BasicFormatter<Char>::format(
template
<
typename
Char
>
void
fmt
::
BasicFormatter
<
Char
>::
format
(
BasicStringRef
<
Char
>
format_str
,
const
ArgList
&
args
)
{
Basic
C
StringRef
<
Char
>
format_str
,
const
ArgList
&
args
)
{
const
Char
*
s
=
start_
=
format_str
.
c_str
();
set_args
(
args
);
while
(
*
s
)
{
...
...
@@ -1106,41 +1250,41 @@ void fmt::BasicFormatter<Char>::format(
if
(
c
==
'}'
)
FMT_THROW
(
FormatError
(
"unmatched '}' in format string"
));
write
(
writer_
,
start_
,
s
-
1
);
Arg
arg
=
parse_arg_index
(
s
);
Arg
arg
=
is_name_start
(
*
s
)
?
parse_arg_name
(
s
)
:
parse_arg_index
(
s
);
s
=
format
(
s
,
arg
);
}
write
(
writer_
,
start_
,
s
);
}
FMT_FUNC
void
fmt
::
report_system_error
(
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
report_error
(
internal
::
format_system_error
,
error_code
,
message
);
}
#if
def _WIN32
#if
FMT_USE_WINDOWS_H
FMT_FUNC
void
fmt
::
report_windows_error
(
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
report_error
(
internal
::
format_windows_error
,
error_code
,
message
);
}
#endif
FMT_FUNC
void
fmt
::
print
(
std
::
FILE
*
f
,
StringRef
format_str
,
ArgList
args
)
{
FMT_FUNC
void
fmt
::
print
(
std
::
FILE
*
f
,
C
StringRef
format_str
,
ArgList
args
)
{
MemoryWriter
w
;
w
.
write
(
format_str
,
args
);
std
::
fwrite
(
w
.
data
(),
1
,
w
.
size
(),
f
);
}
FMT_FUNC
void
fmt
::
print
(
StringRef
format_str
,
ArgList
args
)
{
FMT_FUNC
void
fmt
::
print
(
C
StringRef
format_str
,
ArgList
args
)
{
print
(
stdout
,
format_str
,
args
);
}
FMT_FUNC
void
fmt
::
print
(
std
::
ostream
&
os
,
StringRef
format_str
,
ArgList
args
)
{
FMT_FUNC
void
fmt
::
print
(
std
::
ostream
&
os
,
C
StringRef
format_str
,
ArgList
args
)
{
MemoryWriter
w
;
w
.
write
(
format_str
,
args
);
os
.
write
(
w
.
data
(),
w
.
size
());
}
FMT_FUNC
void
fmt
::
print_colored
(
Color
c
,
StringRef
format
,
ArgList
args
)
{
FMT_FUNC
void
fmt
::
print_colored
(
Color
c
,
C
StringRef
format
,
ArgList
args
)
{
char
escape
[]
=
"
\x1b
[30m"
;
escape
[
3
]
=
'0'
+
static_cast
<
char
>
(
c
);
std
::
fputs
(
escape
,
stdout
);
...
...
@@ -1148,7 +1292,7 @@ FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
std
::
fputs
(
RESET_COLOR
,
stdout
);
}
FMT_FUNC
int
fmt
::
fprintf
(
std
::
FILE
*
f
,
StringRef
format
,
ArgList
args
)
{
FMT_FUNC
int
fmt
::
fprintf
(
std
::
FILE
*
f
,
C
StringRef
format
,
ArgList
args
)
{
MemoryWriter
w
;
printf
(
w
,
format
,
args
);
std
::
size_t
size
=
w
.
size
();
...
...
@@ -1157,6 +1301,8 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
#ifndef FMT_HEADER_ONLY
template
struct
fmt
::
internal
::
BasicData
<
void
>
;
// Explicit instantiations for char.
template
void
fmt
::
internal
::
FixedBuffer
<
char
>::
grow
(
std
::
size_t
);
...
...
@@ -1165,10 +1311,10 @@ template const char *fmt::BasicFormatter<char>::format(
const
char
*&
format_str
,
const
fmt
::
internal
::
Arg
&
arg
);
template
void
fmt
::
BasicFormatter
<
char
>::
format
(
BasicStringRef
<
char
>
format
,
const
ArgList
&
args
);
CStringRef
format
,
const
ArgList
&
args
);
template
void
fmt
::
internal
::
PrintfFormatter
<
char
>::
format
(
BasicWriter
<
char
>
&
writer
,
BasicStringRef
<
char
>
format
,
const
ArgList
&
args
);
BasicWriter
<
char
>
&
writer
,
CStringRef
format
,
const
ArgList
&
args
);
template
int
fmt
::
internal
::
CharTraits
<
char
>::
format_float
(
char
*
buffer
,
std
::
size_t
size
,
const
char
*
format
,
...
...
@@ -1186,10 +1332,10 @@ template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
const
wchar_t
*&
format_str
,
const
fmt
::
internal
::
Arg
&
arg
);
template
void
fmt
::
BasicFormatter
<
wchar_t
>::
format
(
BasicStringRef
<
wchar_t
>
format
,
const
ArgList
&
args
);
Basic
C
StringRef
<
wchar_t
>
format
,
const
ArgList
&
args
);
template
void
fmt
::
internal
::
PrintfFormatter
<
wchar_t
>::
format
(
BasicWriter
<
wchar_t
>
&
writer
,
BasicStringRef
<
wchar_t
>
format
,
BasicWriter
<
wchar_t
>
&
writer
,
WCStringRef
format
,
const
ArgList
&
args
);
template
int
fmt
::
internal
::
CharTraits
<
wchar_t
>::
format_float
(
...
...
include/spdlog/details/format.h
View file @
1c13f5d7
/*
Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
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.
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.
*/
Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
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.
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.
*/
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
...
...
@@ -41,6 +41,7 @@
#include <stdexcept>
#include <string>
#include <sstream>
#include <map>
#if _SECURE_SCL
# include <iterator>
...
...
@@ -154,26 +155,34 @@ inline uint32_t clzll(uint64_t x) {
#endif
// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
#ifndef FMT_NOEXCEPT
# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11)
# define FMT_NOEXCEPT noexcept
#else
#
else
# define FMT_NOEXCEPT throw()
# endif
#endif
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
(FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800
# define FMT_DELETED_OR_UNDEFINED = delete
# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
TypeName& operator=(const TypeName&) = delete
#else
# define FMT_DELETED_OR_UNDEFINED
# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
TypeName& operator=(const TypeName&)
#endif
#ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
namespace
fmt
{
// Fix the warning about long long on older versions of GCC
...
...
@@ -198,71 +207,74 @@ template <typename Char, typename T>
void
format
(
BasicFormatter
<
Char
>
&
f
,
const
Char
*&
format_str
,
const
T
&
value
);
/**
\rst
A string reference. It can be constructed from a C string or
``std::string``.
\rst
A string reference. It can be constructed from a C string or ``std::string``.
You can use one of the following typedefs for common character types:
You can use one of the following typedefs for common character types:
+------------+-------------------------+
| Type | Definition |
+============+=========================+
| StringRef | BasicStringRef<char> |
+------------+-------------------------+
| WStringRef | BasicStringRef<wchar_t> |
+------------+-------------------------+
+------------+-------------------------+
| Type | Definition |
+============+=========================+
| StringRef | BasicStringRef<char> |
+------------+-------------------------+
| WStringRef | BasicStringRef<wchar_t> |
+------------+-------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(StringRef format_str, const Args & ... args);
template <typename... Args>
std::string format(StringRef format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template
<
typename
Char
>
class
BasicStringRef
{
private
:
private
:
const
Char
*
data_
;
std
::
size_t
size_
;
public
:
/**
Constructs a string reference object from a C string and a size.
*/
public
:
/** Constructs a string reference object from a C string and a size. */
BasicStringRef
(
const
Char
*
s
,
std
::
size_t
size
)
:
data_
(
s
),
size_
(
size
)
{}
/**
\rst
Constructs a string reference object from a C string computing
the size with ``std::char_traits<Char>::length``.
\endrst
*/
BasicStringRef
(
const
Char
*
s
)
:
data_
(
s
),
size_
(
std
::
char_traits
<
Char
>::
length
(
s
))
{}
/**
Constructs a string reference from an `std::string` object.
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
BasicStringRef
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
()),
size_
(
s
.
size
())
{}
/**
Converts a string reference to an `std::string` object.
\rst
Converts a string reference to an ``std::string`` object.
\endrst
*/
operator
std
::
basic_string
<
Char
>
()
const
{
return
std
::
basic_string
<
Char
>
(
data_
,
size
()
);
std
::
basic_string
<
Char
>
to_string
()
const
{
return
std
::
basic_string
<
Char
>
(
data_
,
size_
);
}
/**
Returns the pointer to a C string.
*/
const
Char
*
c_str
()
const
{
return
data_
;
}
/** Returns the pointer to a C string. */
const
Char
*
data
()
const
{
return
data_
;
}
/**
Returns the string size.
*/
std
::
size_t
size
()
const
{
return
size_
;
}
/** Returns the string size. */
std
::
size_t
size
()
const
{
return
size_
;
}
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
data_
==
rhs
.
data_
;
...
...
@@ -270,17 +282,72 @@ class BasicStringRef {
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
data_
!=
rhs
.
data_
;
}
friend
bool
operator
<
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
std
::
lexicographical_compare
(
lhs
.
data_
,
lhs
.
data_
+
lhs
.
size_
,
rhs
.
data_
,
rhs
.
data_
+
rhs
.
size_
);
}
};
typedef
BasicStringRef
<
char
>
StringRef
;
typedef
BasicStringRef
<
wchar_t
>
WStringRef
;
/**
\rst
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 typedefs for common character types:
+-------------+--------------------------+
| Type | Definition |
+=============+==========================+
| CStringRef | BasicCStringRef<char> |
+-------------+--------------------------+
| WCStringRef | BasicCStringRef<wchar_t> |
+-------------+--------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(CStringRef format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template
<
typename
Char
>
class
BasicCStringRef
{
private
:
const
Char
*
data_
;
public
:
/** Constructs a string reference object from a C string. */
BasicCStringRef
(
const
Char
*
s
)
:
data_
(
s
)
{}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
BasicCStringRef
(
const
std
::
basic_string
<
Char
>
&
s
)
:
data_
(
s
.
c_str
())
{}
/** Returns the pointer to a C string. */
const
Char
*
c_str
()
const
{
return
data_
;
}
};
typedef
BasicCStringRef
<
char
>
CStringRef
;
typedef
BasicCStringRef
<
wchar_t
>
WCStringRef
;
/**
A formatting error such as invalid format string.
A formatting error such as invalid format string.
*/
class
FormatError
:
public
std
::
runtime_error
{
public
:
explicit
FormatError
(
StringRef
message
)
public
:
explicit
FormatError
(
C
StringRef
message
)
:
std
::
runtime_error
(
message
.
c_str
())
{}
};
...
...
@@ -297,17 +364,23 @@ inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) {
}
#else
template
<
typename
T
>
inline
T
*
make_ptr
(
T
*
ptr
,
std
::
size_t
)
{
return
ptr
;
}
inline
T
*
make_ptr
(
T
*
ptr
,
std
::
size_t
)
{
return
ptr
;
}
#endif
}
// namespace internal
/** A buffer supporting a subset of ``std::vector``'s operations. */
/**
\rst
A buffer supporting a subset of ``std::vector``'s operations.
\endrst
*/
template
<
typename
T
>
class
Buffer
{
private
:
private
:
FMT_DISALLOW_COPY_AND_ASSIGN
(
Buffer
);
protected
:
protected
:
T
*
ptr_
;
std
::
size_t
size_
;
std
::
size_t
capacity_
;
...
...
@@ -316,19 +389,25 @@ class Buffer {
:
ptr_
(
ptr
),
size_
(
0
),
capacity_
(
capacity
)
{}
/**
\rst
Increases the buffer capacity to hold at least *size* elements updating
``ptr_`` and ``capacity_``.
\endrst
*/
virtual
void
grow
(
std
::
size_t
size
)
=
0
;
public
:
public
:
virtual
~
Buffer
()
{}
/** Returns the size of this buffer. */
std
::
size_t
size
()
const
{
return
size_
;
}
std
::
size_t
size
()
const
{
return
size_
;
}
/** Returns the capacity of this buffer. */
std
::
size_t
capacity
()
const
{
return
capacity_
;
}
std
::
size_t
capacity
()
const
{
return
capacity_
;
}
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
...
...
@@ -339,13 +418,17 @@ class Buffer {
size_
=
new_size
;
}
/** Reserves space to store at least *capacity* elements. */
/**
\rst
Reserves space to store at least *capacity* elements.
\endrst
*/
void
reserve
(
std
::
size_t
capacity
)
{
if
(
capacity
>
capacity_
)
grow
(
capacity
);
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
push_back
(
const
T
&
value
)
{
if
(
size_
==
capacity_
)
...
...
@@ -354,14 +437,20 @@ class Buffer {
}
/** Appends data to the end of the buffer. */
void
append
(
const
T
*
begin
,
const
T
*
end
);
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
];
}
T
&
operator
[](
std
::
size_t
index
)
{
return
ptr_
[
index
];
}
const
T
&
operator
[](
std
::
size_t
index
)
const
{
return
ptr_
[
index
];
}
};
template
<
typename
T
>
void
Buffer
<
T
>::
append
(
const
T
*
begin
,
const
T
*
end
)
{
template
<
typename
U
>
void
Buffer
<
T
>::
append
(
const
U
*
begin
,
const
U
*
end
)
{
std
::
ptrdiff_t
num_elements
=
end
-
begin
;
if
(
size_
+
num_elements
>
capacity_
)
grow
(
size_
+
num_elements
);
...
...
@@ -375,7 +464,7 @@ namespace internal {
// the object itself.
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
=
std
::
allocator
<
T
>
>
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
private
:
private
:
T
data_
[
SIZE
];
// Free memory allocated by the buffer.
...
...
@@ -383,16 +472,18 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
if
(
this
->
ptr_
!=
data_
)
this
->
deallocate
(
this
->
ptr_
,
this
->
capacity_
);
}
protected
:
protected
:
void
grow
(
std
::
size_t
size
);
public
:
public
:
explicit
MemoryBuffer
(
const
Allocator
&
alloc
=
Allocator
())
:
Allocator
(
alloc
),
Buffer
<
T
>
(
data_
,
SIZE
)
{}
~
MemoryBuffer
()
{
free
();
}
~
MemoryBuffer
()
{
free
();
}
#if FMT_USE_RVALUE_REFERENCES
private
:
private
:
// Move data from other to this buffer.
void
move
(
MemoryBuffer
&
other
)
{
Allocator
&
this_alloc
=
*
this
,
&
other_alloc
=
other
;
...
...
@@ -403,7 +494,8 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
this
->
ptr_
=
data_
;
std
::
copy
(
other
.
data_
,
other
.
data_
+
this
->
size_
,
make_ptr
(
data_
,
this
->
capacity_
));
}
else
{
}
else
{
this
->
ptr_
=
other
.
ptr_
;
// Set pointer to the inline array so that delete is not called
// when freeing.
...
...
@@ -411,7 +503,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
}
}
public
:
public
:
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
move
(
other
);
}
...
...
@@ -425,7 +517,9 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
#endif
// Returns a copy of the allocator associated with this buffer.
Allocator
get_allocator
()
const
{
return
*
this
;
}
Allocator
get_allocator
()
const
{
return
*
this
;
}
};
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
>
...
...
@@ -450,10 +544,10 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
// A fixed-size buffer.
template
<
typename
Char
>
class
FixedBuffer
:
public
fmt
::
Buffer
<
Char
>
{
public
:
public
:
FixedBuffer
(
Char
*
array
,
std
::
size_t
size
)
:
fmt
::
Buffer
<
Char
>
(
array
,
size
)
{}
protected
:
protected
:
void
grow
(
std
::
size_t
size
);
};
...
...
@@ -471,11 +565,19 @@ inline int getsign(double x) {
// Portable version of isinf.
# ifdef isinf
inline
int
isinfinity
(
double
x
)
{
return
isinf
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
isinf
(
x
);
}
inline
int
isinfinity
(
double
x
)
{
return
isinf
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
isinf
(
x
);
}
# else
inline
int
isinfinity
(
double
x
)
{
return
std
::
isinf
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
std
::
isinf
(
x
);
}
inline
int
isinfinity
(
double
x
)
{
return
std
::
isinf
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
std
::
isinf
(
x
);
}
# endif
#else
inline
int
getsign
(
double
value
)
{
...
...
@@ -486,18 +588,25 @@ inline int getsign(double value) {
_ecvt_s
(
buffer
,
sizeof
(
buffer
),
value
,
0
,
&
dec
,
&
sign
);
return
sign
;
}
inline
int
isinfinity
(
double
x
)
{
return
!
_finite
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
!
_finite
(
static_cast
<
double
>
(
x
));
}
inline
int
isinfinity
(
double
x
)
{
return
!
_finite
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
!
_finite
(
static_cast
<
double
>
(
x
));
}
#endif
template
<
typename
Char
>
class
BasicCharTraits
{
public
:
public
:
#if _SECURE_SCL
typedef
stdext
::
checked_array_iterator
<
Char
*>
CharPtr
;
#else
typedef
Char
*
CharPtr
;
#endif
static
Char
cast
(
wchar_t
value
)
{
return
static_cast
<
Char
>
(
value
);
}
};
template
<
typename
Char
>
...
...
@@ -505,12 +614,14 @@ class CharTraits;
template
<>
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
private
:
private
:
// Conversion from wchar_t to char is not allowed.
static
char
convert
(
wchar_t
);
public
:
static
char
convert
(
char
value
)
{
return
value
;
}
static
char
convert
(
char
value
)
{
return
value
;
}
// Formats a floating-point number.
template
<
typename
T
>
...
...
@@ -520,9 +631,13 @@ public:
template
<>
class
CharTraits
<
wchar_t
>
:
public
BasicCharTraits
<
wchar_t
>
{
public
:
static
wchar_t
convert
(
char
value
)
{
return
value
;
}
static
wchar_t
convert
(
wchar_t
value
)
{
return
value
;
}
public
:
static
wchar_t
convert
(
char
value
)
{
return
value
;
}
static
wchar_t
convert
(
wchar_t
value
)
{
return
value
;
}
template
<
typename
T
>
static
int
format_float
(
wchar_t
*
buffer
,
std
::
size_t
size
,
...
...
@@ -533,13 +648,17 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
template
<
bool
IsSigned
>
struct
SignChecker
{
template
<
typename
T
>
static
bool
is_negative
(
T
value
)
{
return
value
<
0
;
}
static
bool
is_negative
(
T
value
)
{
return
value
<
0
;
}
};
template
<>
struct
SignChecker
<
false
>
{
template
<
typename
T
>
static
bool
is_negative
(
T
)
{
return
false
;
}
static
bool
is_negative
(
T
)
{
return
false
;
}
};
// Returns true if value is negative, false otherwise.
...
...
@@ -551,10 +670,14 @@ inline bool is_negative(T value) {
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
template
<
bool
FitsIn32Bits
>
struct
TypeSelector
{
typedef
uint32_t
Type
;
};
struct
TypeSelector
{
typedef
uint32_t
Type
;
};
template
<>
struct
TypeSelector
<
false
>
{
typedef
uint64_t
Type
;
};
struct
TypeSelector
<
false
>
{
typedef
uint64_t
Type
;
};
template
<
typename
T
>
struct
IntTraits
{
...
...
@@ -566,7 +689,9 @@ struct IntTraits {
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template
<
typename
T
>
struct
MakeUnsigned
{
typedef
T
Type
;
};
struct
MakeUnsigned
{
typedef
T
Type
;
};
#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
template <> \
...
...
@@ -658,56 +783,71 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
buffer
[
0
]
=
Data
::
DIGITS
[
index
];
}
#ifdef _WIN32
#ifndef _WIN32
# define FMT_USE_WINDOWS_H 0
#elif !defined(FMT_USE_WINDOWS_H)
# define FMT_USE_WINDOWS_H 1
#endif
// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
// All the functionality that relies on it will be disabled too.
#if FMT_USE_WINDOWS_H
// A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF8ToUTF16
{
private
:
private
:
MemoryBuffer
<
wchar_t
,
INLINE_BUFFER_SIZE
>
buffer_
;
public
:
public
:
explicit
UTF8ToUTF16
(
StringRef
s
);
operator
WStringRef
()
const
{
return
WStringRef
(
&
buffer_
[
0
],
size
());
}
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
}
const
wchar_t
*
c_str
()
const
{
return
&
buffer_
[
0
];
}
std
::
wstring
str
()
const
{
return
std
::
wstring
(
&
buffer_
[
0
],
size
());
}
operator
WStringRef
()
const
{
return
WStringRef
(
&
buffer_
[
0
],
size
());
}
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
}
const
wchar_t
*
c_str
()
const
{
return
&
buffer_
[
0
];
}
std
::
wstring
str
()
const
{
return
std
::
wstring
(
&
buffer_
[
0
],
size
());
}
};
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF16ToUTF8
{
private
:
private
:
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer_
;
public
:
public
:
UTF16ToUTF8
()
{}
explicit
UTF16ToUTF8
(
WStringRef
s
);
operator
StringRef
()
const
{
return
StringRef
(
&
buffer_
[
0
],
size
());
}
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
}
const
char
*
c_str
()
const
{
return
&
buffer_
[
0
];
}
std
::
string
str
()
const
{
return
std
::
string
(
&
buffer_
[
0
],
size
());
}
operator
StringRef
()
const
{
return
StringRef
(
&
buffer_
[
0
],
size
());
}
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
}
const
char
*
c_str
()
const
{
return
&
buffer_
[
0
];
}
std
::
string
str
()
const
{
return
std
::
string
(
&
buffer_
[
0
],
size
());
}
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
int
convert
(
WStringRef
s
);
};
#endif
void
format_system_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
;
#ifdef _WIN32
void
format_windows_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
;
#endif
// Computes max(N, 1) at compile time. It is used to avoid errors about
// allocating an array of 0 size.
template
<
unsigned
N
>
struct
NonZero
{
enum
{
VALUE
=
N
>
0
?
N
:
1
};
};
void
format_system_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
;
// A formatting argument value.
struct
Value
{
...
...
@@ -717,7 +857,7 @@ struct Value {
std
::
size_t
size
;
};
typedef
void
(
*
FormatFunc
)(
typedef
void
(
*
FormatFunc
)(
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
);
struct
CustomValue
{
...
...
@@ -741,9 +881,9 @@ struct Value {
};
enum
Type
{
NONE
,
NONE
,
NAMED_ARG
,
// Integer types should go first,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
BOOL
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
// followed by floating-point types.
DOUBLE
,
LONG_DOUBLE
,
LAST_NUMERIC_TYPE
=
LONG_DOUBLE
,
CSTRING
,
STRING
,
WSTRING
,
POINTER
,
CUSTOM
...
...
@@ -756,26 +896,29 @@ struct Arg : Value {
Type
type
;
};
template
<
typename
Char
>
struct
NamedArg
;
template
<
typename
T
=
void
>
struct
N
one
{};
struct
N
ull
{};
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
template
<
typename
T
,
typename
Char
>
struct
WCharHelper
{
typedef
None
<
T
>
Supported
;
typedef
Null
<
T
>
Supported
;
typedef
T
Unsupported
;
};
template
<
typename
T
>
struct
WCharHelper
<
T
,
wchar_t
>
{
typedef
T
Supported
;
typedef
None
<
T
>
Unsupported
;
typedef
Null
<
T
>
Unsupported
;
};
template
<
typename
T
>
class
IsConvertibleToInt
{
private
:
private
:
typedef
char
yes
[
1
];
typedef
char
no
[
2
];
...
...
@@ -784,7 +927,7 @@ class IsConvertibleToInt {
static
yes
&
check
(
fmt
::
ULongLong
);
static
no
&
check
(...);
public
:
public
:
enum
{
value
=
(
sizeof
(
check
(
get
()))
==
sizeof
(
yes
))
};
};
...
...
@@ -804,22 +947,30 @@ template<bool B, class T = void>
struct
EnableIf
{};
template
<
class
T
>
struct
EnableIf
<
true
,
T
>
{
typedef
T
type
;
};
struct
EnableIf
<
true
,
T
>
{
typedef
T
type
;
};
template
<
bool
B
,
class
T
,
class
F
>
struct
Conditional
{
typedef
T
type
;
};
struct
Conditional
{
typedef
T
type
;
};
template
<
class
T
,
class
F
>
struct
Conditional
<
false
,
T
,
F
>
{
typedef
F
type
;
};
struct
Conditional
<
false
,
T
,
F
>
{
typedef
F
type
;
};
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
inline
bool
check
(
bool
value
)
{
return
value
;
}
inline
bool
check
(
bool
value
)
{
return
value
;
}
// Makes an Arg object from any type.
template
<
typename
Char
>
class
MakeValue
:
public
Arg
{
private
:
private
:
// The following two methods are private to disallow formatting of
// arbitrary pointers. If you want to output a pointer cast it to
// "void *" or "const void *". In particular, this forbids formatting
...
...
@@ -841,12 +992,12 @@ class MakeValue : public Arg {
MakeValue
(
typename
WCharHelper
<
WStringRef
,
Char
>::
Unsupported
);
void
set_string
(
StringRef
str
)
{
string
.
value
=
str
.
c_str
();
string
.
value
=
str
.
data
();
string
.
size
=
str
.
size
();
}
void
set_string
(
WStringRef
str
)
{
wstring
.
value
=
str
.
c_str
();
wstring
.
value
=
str
.
data
();
wstring
.
size
=
str
.
size
();
}
...
...
@@ -859,14 +1010,17 @@ class MakeValue : public Arg {
*
static_cast
<
const
T
*>
(
arg
));
}
public
:
public
:
MakeValue
()
{}
#define FMT_MAKE_VALUE
(Type, field, TYPE
) \
MakeValue(Type value) { field =
value
; } \
#define FMT_MAKE_VALUE
_(Type, field, TYPE, rhs
) \
MakeValue(Type value) { field =
rhs
; } \
static uint64_t type(Type) { return Arg::TYPE; }
FMT_MAKE_VALUE
(
bool
,
int_value
,
INT
)
#define FMT_MAKE_VALUE(Type, field, TYPE) \
FMT_MAKE_VALUE_(Type, field, TYPE, value)
FMT_MAKE_VALUE
(
bool
,
int_value
,
BOOL
)
FMT_MAKE_VALUE
(
short
,
int_value
,
INT
)
FMT_MAKE_VALUE
(
unsigned
short
,
uint_value
,
UINT
)
FMT_MAKE_VALUE
(
int
,
int_value
,
INT
)
...
...
@@ -907,7 +1061,9 @@ class MakeValue : public Arg {
MakeValue
(
typename
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
int_value
=
value
;
}
static
uint64_t
type
(
wchar_t
)
{
return
Arg
::
CHAR
;
}
static
uint64_t
type
(
wchar_t
)
{
return
Arg
::
CHAR
;
}
#define FMT_MAKE_STR_VALUE(Type, TYPE) \
MakeValue(Type value) { set_string(value); } \
...
...
@@ -919,6 +1075,7 @@ class MakeValue : public Arg {
FMT_MAKE_VALUE
(
const
unsigned
char
*
,
ustring
.
value
,
CSTRING
)
FMT_MAKE_STR_VALUE
(
const
std
::
string
&
,
STRING
)
FMT_MAKE_STR_VALUE
(
StringRef
,
STRING
)
FMT_MAKE_VALUE_
(
CStringRef
,
string
.
value
,
CSTRING
,
value
.
c_str
())
#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \
MakeValue(typename WCharHelper<Type, Char>::Supported value) { \
...
...
@@ -951,6 +1108,29 @@ class MakeValue : public Arg {
static
uint64_t
type
(
const
T
&
)
{
return
IsConvertibleToInt
<
T
>::
value
?
Arg
::
INT
:
Arg
::
CUSTOM
;
}
// Additional template param `Char_` is needed here because make_type always
// uses MakeValue<char>.
template
<
typename
Char_
>
MakeValue
(
const
NamedArg
<
Char_
>
&
value
)
{
pointer
=
&
value
;
}
template
<
typename
Char_
>
static
uint64_t
type
(
const
NamedArg
<
Char_
>
&
)
{
return
Arg
::
NAMED_ARG
;
}
};
template
<
typename
Char
>
struct
NamedArg
:
Arg
{
BasicStringRef
<
Char
>
name
;
template
<
typename
T
>
NamedArg
(
BasicStringRef
<
Char
>
name
,
const
T
&
value
)
:
name
(
name
),
Arg
(
MakeValue
<
Char
>
(
value
))
{
type
=
static_cast
<
internal
::
Arg
::
Type
>
(
MakeValue
<
Char
>::
type
(
value
));
}
};
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
...
...
@@ -977,7 +1157,7 @@ class MakeValue : public Arg {
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template
<
typename
Impl
,
typename
Result
>
class
ArgVisitor
{
public
:
public
:
void
report_unhandled_arg
()
{}
Result
visit_unhandled_arg
()
{
...
...
@@ -997,6 +1177,9 @@ class ArgVisitor {
Result
visit_ulong_long
(
ULongLong
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
Result
visit_bool
(
bool
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
Result
visit_char
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
...
...
@@ -1032,7 +1215,7 @@ class ArgVisitor {
Result
visit
(
const
Arg
&
arg
)
{
switch
(
arg
.
type
)
{
default
:
assert
(
false
);
FMT_ASSERT
(
false
,
"invalid argument type"
);
return
Result
();
case
Arg
:
:
INT
:
return
FMT_DISPATCH
(
visit_int
(
arg
.
int_value
));
...
...
@@ -1042,12 +1225,14 @@ class ArgVisitor {
return
FMT_DISPATCH
(
visit_long_long
(
arg
.
long_long_value
));
case
Arg
:
:
ULONG_LONG
:
return
FMT_DISPATCH
(
visit_ulong_long
(
arg
.
ulong_long_value
));
case
Arg
:
:
BOOL
:
return
FMT_DISPATCH
(
visit_bool
(
arg
.
int_value
!=
0
));
case
Arg
:
:
CHAR
:
return
FMT_DISPATCH
(
visit_char
(
arg
.
int_value
));
case
Arg
:
:
DOUBLE
:
return
FMT_DISPATCH
(
visit_double
(
arg
.
double_value
));
case
Arg
:
:
LONG_DOUBLE
:
return
FMT_DISPATCH
(
visit_long_double
(
arg
.
long_double_value
));
case
Arg
:
:
CHAR
:
return
FMT_DISPATCH
(
visit_char
(
arg
.
int_value
));
case
Arg
:
:
CSTRING
:
{
Arg
::
StringValue
<
char
>
str
=
arg
.
string
;
str
.
size
=
0
;
...
...
@@ -1066,17 +1251,23 @@ class ArgVisitor {
};
class
RuntimeError
:
public
std
::
runtime_error
{
protected
:
protected
:
RuntimeError
()
:
std
::
runtime_error
(
""
)
{}
};
template
<
typename
Impl
,
typename
Char
>
class
BasicArgFormatter
;
template
<
typename
Char
>
class
PrintfArgFormatter
;
template
<
typename
Char
>
class
Arg
Formatter
;
class
Arg
Map
;
}
// namespace internal
/** An argument list. */
class
ArgList
{
private
:
private
:
// To reduce compiled code size per formatting function call, types of first
// MAX_PACKED_ARGS arguments are passed in the types_ field.
uint64_t
types_
;
...
...
@@ -1097,13 +1288,15 @@ class ArgList {
(
types_
&
(
mask
<<
shift
))
>>
shift
);
}
public
:
template
<
typename
Char
>
friend
class
internal
::
ArgMap
;
public
:
// Maximum number of arguments with packed types.
enum
{
MAX_PACKED_ARGS
=
16
};
ArgList
()
:
types_
(
0
)
{}
// TODO: MakeArgList(const Args &...)
ArgList
(
ULongLong
types
,
const
internal
::
Value
*
values
)
:
types_
(
types
),
values_
(
values
)
{}
ArgList
(
ULongLong
types
,
const
internal
::
Arg
*
args
)
...
...
@@ -1140,21 +1333,36 @@ struct FormatSpec;
namespace
internal
{
template
<
std
::
size_t
NUM_ARGS
>
struct
SelectValueType
{
typedef
typename
Conditional
<
(
NUM_ARGS
<
ArgList
::
MAX_PACKED_ARGS
),
Value
,
Arg
>::
type
Type
;
template
<
typename
Char
>
class
ArgMap
{
private
:
typedef
std
::
map
<
fmt
::
BasicStringRef
<
Char
>
,
internal
::
Arg
>
MapType
;
typedef
typename
MapType
::
value_type
Pair
;
MapType
map_
;
public
:
void
init
(
const
ArgList
&
args
);
const
internal
::
Arg
*
find
(
const
fmt
::
BasicStringRef
<
Char
>
&
name
)
const
{
typename
MapType
::
const_iterator
it
=
map_
.
find
(
name
);
return
it
!=
map_
.
end
()
?
&
it
->
second
:
0
;
}
};
class
FormatterBase
{
private
:
private
:
ArgList
args_
;
int
next_arg_index_
;
// Returns the argument with specified index.
Arg
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
protected
:
protected
:
const
ArgList
&
args
()
const
{
return
args_
;
}
void
set_args
(
const
ArgList
&
args
)
{
args_
=
args
;
next_arg_index_
=
0
;
...
...
@@ -1167,6 +1375,8 @@ class FormatterBase {
// specified index.
Arg
get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
bool
check_no_auto_index
(
const
char
*&
error
);
template
<
typename
Char
>
void
write
(
BasicWriter
<
Char
>
&
w
,
const
Char
*
start
,
const
Char
*
end
)
{
if
(
start
!=
end
)
...
...
@@ -1177,7 +1387,7 @@ class FormatterBase {
// A printf formatter.
template
<
typename
Char
>
class
PrintfFormatter
:
private
FormatterBase
{
private
:
private
:
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
// Returns the argument with specified index or, if arg_index is equal
...
...
@@ -1188,30 +1398,42 @@ class PrintfFormatter : private FormatterBase {
// Parses argument index, flags and width and returns the argument index.
unsigned
parse_header
(
const
Char
*&
s
,
FormatSpec
&
spec
);
public
:
public
:
void
format
(
BasicWriter
<
Char
>
&
writer
,
Basic
StringRef
<
Char
>
format_str
,
const
ArgList
&
args
);
BasicC
StringRef
<
Char
>
format_str
,
const
ArgList
&
args
);
};
}
// namespace internal
// A formatter.
template
<
typename
Char
>
class
BasicFormatter
:
private
internal
::
FormatterBase
{
private
:
private
:
BasicWriter
<
Char
>
&
writer_
;
const
Char
*
start_
;
internal
::
ArgMap
<
Char
>
map_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
BasicFormatter
);
using
FormatterBase
::
get_arg
;
// Checks if manual indexing is used and returns the argument with
// specified name.
internal
::
Arg
get_arg
(
BasicStringRef
<
Char
>
arg_name
,
const
char
*&
error
);
// Parses argument index and returns corresponding argument.
internal
::
Arg
parse_arg_index
(
const
Char
*&
s
);
public
:
// Parses argument name and returns corresponding argument.
internal
::
Arg
parse_arg_name
(
const
Char
*&
s
);
public
:
explicit
BasicFormatter
(
BasicWriter
<
Char
>
&
w
)
:
writer_
(
w
)
{}
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
}
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
}
void
format
(
Basic
StringRef
<
Char
>
format_str
,
const
ArgList
&
args
);
void
format
(
BasicC
StringRef
<
Char
>
format_str
,
const
ArgList
&
args
);
const
Char
*
format
(
const
Char
*&
format_str
,
const
internal
::
Arg
&
arg
);
};
...
...
@@ -1232,12 +1454,24 @@ struct EmptySpec {};
// A type specifier.
template
<
char
TYPE
>
struct
TypeSpec
:
EmptySpec
{
Alignment
align
()
const
{
return
ALIGN_DEFAULT
;
}
unsigned
width
()
const
{
return
0
;
}
int
precision
()
const
{
return
-
1
;
}
bool
flag
(
unsigned
)
const
{
return
false
;
}
char
type
()
const
{
return
TYPE
;
}
char
fill
()
const
{
return
' '
;
}
Alignment
align
()
const
{
return
ALIGN_DEFAULT
;
}
unsigned
width
()
const
{
return
0
;
}
int
precision
()
const
{
return
-
1
;
}
bool
flag
(
unsigned
)
const
{
return
false
;
}
char
type
()
const
{
return
TYPE
;
}
char
fill
()
const
{
return
' '
;
}
};
// A width specifier.
...
...
@@ -1249,8 +1483,12 @@ struct WidthSpec {
WidthSpec
(
unsigned
width
,
wchar_t
fill
)
:
width_
(
width
),
fill_
(
fill
)
{}
unsigned
width
()
const
{
return
width_
;
}
wchar_t
fill
()
const
{
return
fill_
;
}
unsigned
width
()
const
{
return
width_
;
}
wchar_t
fill
()
const
{
return
fill_
;
}
};
// An alignment specifier.
...
...
@@ -1260,9 +1498,13 @@ struct AlignSpec : WidthSpec {
AlignSpec
(
unsigned
width
,
wchar_t
fill
,
Alignment
align
=
ALIGN_DEFAULT
)
:
WidthSpec
(
width
,
fill
),
align_
(
align
)
{}
Alignment
align
()
const
{
return
align_
;
}
Alignment
align
()
const
{
return
align_
;
}
int
precision
()
const
{
return
-
1
;
}
int
precision
()
const
{
return
-
1
;
}
};
// An alignment and type specifier.
...
...
@@ -1270,8 +1512,12 @@ template <char TYPE>
struct
AlignTypeSpec
:
AlignSpec
{
AlignTypeSpec
(
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
)
{}
bool
flag
(
unsigned
)
const
{
return
false
;
}
char
type
()
const
{
return
TYPE
;
}
bool
flag
(
unsigned
)
const
{
return
false
;
}
char
type
()
const
{
return
TYPE
;
}
};
// A full format specifier.
...
...
@@ -1284,73 +1530,86 @@ struct FormatSpec : AlignSpec {
unsigned
width
=
0
,
char
type
=
0
,
wchar_t
fill
=
' '
)
:
AlignSpec
(
width
,
fill
),
flags_
(
0
),
precision_
(
-
1
),
type_
(
type
)
{}
bool
flag
(
unsigned
f
)
const
{
return
(
flags_
&
f
)
!=
0
;
}
int
precision
()
const
{
return
precision_
;
}
char
type
()
const
{
return
type_
;
}
bool
flag
(
unsigned
f
)
const
{
return
(
flags_
&
f
)
!=
0
;
}
int
precision
()
const
{
return
precision_
;
}
char
type
()
const
{
return
type_
;
}
};
// An integer format specifier.
template
<
typename
T
,
typename
SpecT
=
TypeSpec
<
0
>
,
typename
Char
=
char
>
class
IntFormatSpec
:
public
SpecT
{
private
:
private
:
T
value_
;
public
:
public
:
IntFormatSpec
(
T
val
,
const
SpecT
&
spec
=
SpecT
())
:
SpecT
(
spec
),
value_
(
val
)
{}
T
value
()
const
{
return
value_
;
}
T
value
()
const
{
return
value_
;
}
};
// A string format specifier.
template
<
typename
T
>
template
<
typename
Char
>
class
StrFormatSpec
:
public
AlignSpec
{
private
:
const
T
*
str_
;
private
:
const
Char
*
str_
;
public
:
StrFormatSpec
(
const
T
*
str
,
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{}
public
:
template
<
typename
FillChar
>
StrFormatSpec
(
const
Char
*
str
,
unsigned
width
,
FillChar
fill
)
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
}
const
T
*
str
()
const
{
return
str_
;
}
const
Char
*
str
()
const
{
return
str_
;
}
};
/**
Returns an integer format specifier to format the value in base 2.
*/
Returns an integer format specifier to format the value in base 2.
*/
IntFormatSpec
<
int
,
TypeSpec
<
'b'
>
>
bin
(
int
value
);
/**
Returns an integer format specifier to format the value in base 8.
*/
Returns an integer format specifier to format the value in base 8.
*/
IntFormatSpec
<
int
,
TypeSpec
<
'o'
>
>
oct
(
int
value
);
/**
Returns an integer format specifier to format the value in base 16 using
lower-case letters for the digits above 9.
*/
Returns an integer format specifier to format the value in base 16 using
lower-case letters for the digits above 9.
*/
IntFormatSpec
<
int
,
TypeSpec
<
'x'
>
>
hex
(
int
value
);
/**
Returns an integer formatter format specifier to format in base 16 using
upper-case letters for the digits above 9.
*/
Returns an integer formatter format specifier to format in base 16 using
upper-case letters for the digits above 9.
*/
IntFormatSpec
<
int
,
TypeSpec
<
'X'
>
>
hexu
(
int
value
);
/**
\rst
Returns an integer format specifier to pad the formatted argument with the
fill character to the specified width using the default (right) numeric
alignment.
\rst
Returns an integer format specifier to pad the formatted argument with the
fill character to the specified width using the default (right) numeric
alignment.
**Example**::
**Example**::
MemoryWriter out;
out << pad(hex(0xcafe), 8, '0');
// out.str() == "0000cafe"
MemoryWriter out;
out << pad(hex(0xcafe), 8, '0');
// out.str() == "0000cafe"
\endrst
*/
\endrst
*/
template
<
char
TYPE_CODE
,
typename
Char
>
IntFormatSpec
<
int
,
AlignTypeSpec
<
TYPE_CODE
>
,
Char
>
pad
(
int
value
,
unsigned
width
,
Char
fill
=
' '
);
...
...
@@ -1358,26 +1617,26 @@ IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad(
#define FMT_DEFINE_INT_FORMATTERS(TYPE) \
inline IntFormatSpec<TYPE, TypeSpec<'b'> > bin(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'b'> >(value, TypeSpec<'b'>()); \
} \
} \
\
inline IntFormatSpec<TYPE, TypeSpec<'o'> > oct(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'o'> >(value, TypeSpec<'o'>()); \
} \
} \
\
inline IntFormatSpec<TYPE, TypeSpec<'x'> > hex(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'x'> >(value, TypeSpec<'x'>()); \
} \
} \
\
inline IntFormatSpec<TYPE, TypeSpec<'X'> > hexu(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'X'> >(value, TypeSpec<'X'>()); \
} \
} \
\
template <char TYPE_CODE> \
inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> > pad( \
IntFormatSpec<TYPE, TypeSpec<TYPE_CODE> > f, unsigned width) { \
return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> >( \
f.value(), AlignTypeSpec<TYPE_CODE>(width, ' ')); \
} \
} \
\
/* For compatibility with older compilers we provide two overloads for pad, */
\
/* one that takes a fill character and one that doesn't. In the future this */
\
...
...
@@ -1389,20 +1648,20 @@ inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char> pad( \
unsigned width, Char fill) { \
return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char>( \
f.value(), AlignTypeSpec<TYPE_CODE>(width, fill)); \
} \
} \
\
inline IntFormatSpec<TYPE, AlignTypeSpec<0> > pad( \
TYPE value, unsigned width) { \
return IntFormatSpec<TYPE, AlignTypeSpec<0> >( \
value, AlignTypeSpec<0>(width, ' ')); \
} \
} \
\
template <typename Char> \
inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad( \
TYPE value, unsigned width, Char fill) { \
return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>( \
value, AlignTypeSpec<0>(width, fill)); \
}
}
FMT_DEFINE_INT_FORMATTERS
(
int
)
FMT_DEFINE_INT_FORMATTERS
(
long
)
...
...
@@ -1412,17 +1671,17 @@ FMT_DEFINE_INT_FORMATTERS(LongLong)
FMT_DEFINE_INT_FORMATTERS
(
ULongLong
)
/**
\rst
Returns a string formatter that pads the formatted argument with the fill
character to the specified width using the default (left) string alignment.
\rst
Returns a string formatter that pads the formatted argument with the fill
character to the specified width using the default (left) string alignment.
**Example**::
**Example**::
std::string s = str(MemoryWriter() << pad("abc", 8));
// s == "abc "
std::string s = str(MemoryWriter() << pad("abc", 8));
// s == "abc "
\endrst
*/
\endrst
*/
template
<
typename
Char
>
inline
StrFormatSpec
<
Char
>
pad
(
const
Char
*
str
,
unsigned
width
,
Char
fill
=
' '
)
{
...
...
@@ -1454,16 +1713,73 @@ inline StrFormatSpec<wchar_t> pad(
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace
internal
{
inline
uint64_t
make_type
()
{
return
0
;
}
inline
uint64_t
make_type
()
{
return
0
;
}
template
<
typename
T
>
inline
uint64_t
make_type
(
const
T
&
arg
)
{
return
MakeValue
<
char
>::
type
(
arg
);
}
inline
uint64_t
make_type
(
const
T
&
arg
)
{
return
MakeValue
<
char
>::
type
(
arg
);
}
template
<
unsigned
N
>
struct
ArgArray
{
// Computes the argument array size by adding 1 to N, which is the number of
// arguments, if N is zero, because array of zero size is invalid, or if N
// is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
// argument that marks the end of the list.
enum
{
SIZE
=
N
+
(
N
==
0
||
N
>=
ArgList
::
MAX_PACKED_ARGS
?
1
:
0
)
};
typedef
typename
Conditional
<
(
N
<
ArgList
::
MAX_PACKED_ARGS
),
Value
,
Arg
>::
type
Type
[
SIZE
];
};
#if FMT_USE_VARIADIC_TEMPLATES
template
<
typename
Arg
,
typename
...
Args
>
inline
uint64_t
make_type
(
const
Arg
&
first
,
const
Args
&
...
tail
)
{
return
make_type
(
first
)
|
(
make_type
(
tail
...)
<<
4
);
}
inline
void
do_set_types
(
Arg
*
)
{}
template
<
typename
T
,
typename
...
Args
>
inline
void
do_set_types
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
args
->
type
=
static_cast
<
Arg
::
Type
>
(
MakeValue
<
T
>::
type
(
arg
));
do_set_types
(
args
+
1
,
tail
...);
}
template
<
typename
...
Args
>
inline
void
set_types
(
Arg
*
array
,
const
Args
&
...
args
)
{
if
(
check
(
sizeof
...(
Args
)
>
ArgList
::
MAX_PACKED_ARGS
))
do_set_types
(
array
,
args
...);
array
[
sizeof
...(
Args
)].
type
=
Arg
::
NONE
;
}
template
<
typename
...
Args
>
inline
void
set_types
(
Value
*
,
const
Args
&
...)
{
// Do nothing as types are passed separately from values.
}
template
<
typename
Char
,
typename
Value
>
inline
void
store_args
(
Value
*
)
{}
template
<
typename
Char
,
typename
Arg
,
typename
T
,
typename
...
Args
>
inline
void
store_args
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
// Assign only the Value subobject of Arg and don't overwrite type (if any)
// that is assigned by set_types.
Value
&
value
=
*
args
;
value
=
MakeValue
<
Char
>
(
arg
);
store_args
<
Char
>
(
args
+
1
,
tail
...);
}
template
<
typename
Char
,
typename
...
Args
>
ArgList
make_arg_list
(
typename
ArgArray
<
sizeof
...(
Args
)
>::
Type
array
,
const
Args
&
...
args
)
{
if
(
check
(
sizeof
...(
Args
)
>=
ArgList
::
MAX_PACKED_ARGS
))
set_types
(
array
,
args
...);
store_args
<
Char
>
(
array
,
args
...);
return
ArgList
(
make_type
(
args
...),
array
);
}
#else
struct
ArgType
{
...
...
@@ -1497,24 +1813,16 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
# define FMT_VARIADIC_VOID(func, arg_type) \
template <typename... Args> \
void func(arg_type arg0, const Args & ... args) { \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
const Value array[internal::NonZero<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
func(arg0, ArgList(internal::make_type(args...), array)); \
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
func(arg0, fmt::internal::make_arg_list<Char>(array, args...)); \
}
// Defines a variadic constructor.
# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
template <typename... Args> \
ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
const Value array[internal::NonZero<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
func(arg0, arg1, ArgList(internal::make_type(args...), array)); \
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
func(arg0, arg1, fmt::internal::make_arg_list<Char>(array, args...)); \
}
#else
...
...
@@ -1527,9 +1835,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
# define FMT_WRAP1(func, arg_type, n) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::
Value values[]
= {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::
ArgArray<n>::Type array
= {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)),
values
)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)),
array
)); \
}
// Emulates a variadic function returning void on a pre-C++11 compiler.
...
...
@@ -1544,9 +1852,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::
Value values[]
= {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::
ArgArray<n>::Type array
= {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg0, arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)),
values
)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)),
array
)); \
}
// Emulates a variadic constructor on a pre-C++11 compiler.
...
...
@@ -1586,21 +1894,21 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9)
/**
An error returned by an operating system or a language runtime,
for example a file opening error.
An error returned by an operating system or a language runtime,
for example a file opening error.
*/
class
SystemError
:
public
internal
::
RuntimeError
{
private
:
void
init
(
int
err_code
,
StringRef
format_str
,
ArgList
args
);
private
:
void
init
(
int
err_code
,
C
StringRef
format_str
,
ArgList
args
);
protected
:
protected
:
int
error_code_
;
typedef
char
Char
;
// For FMT_VARIADIC_CTOR.
SystemError
()
{}
public
:
public
:
/**
\rst
Constructs a :class:`fmt::SystemError` object with the description
...
...
@@ -1626,35 +1934,37 @@ class SystemError : public internal::RuntimeError {
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst
*/
SystemError
(
int
error_code
,
StringRef
message
)
{
SystemError
(
int
error_code
,
C
StringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
}
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
StringRef
)
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
C
StringRef
)
int
error_code
()
const
{
return
error_code_
;
}
int
error_code
()
const
{
return
error_code_
;
}
};
/**
\rst
This template provides operations for formatting and writing data into
a character stream. The output is stored in a buffer provided by a subclass
such as :class:`fmt::BasicMemoryWriter`.
You can use one of the following typedefs for common character types:
+---------+----------------------+
| Type | Definition |
+=========+======================+
| Writer | BasicWriter<char> |
+---------+----------------------+
| WWriter | BasicWriter<wchar_t> |
+---------+----------------------+
\endrst
*/
\rst
This template provides operations for formatting and writing data into
a character stream. The output is stored in a buffer provided by a subclass
such as :class:`fmt::BasicMemoryWriter`.
You can use one of the following typedefs for common character types:
+---------+----------------------+
| Type | Definition |
+=========+======================+
| Writer | BasicWriter<char> |
+---------+----------------------+
| WWriter | BasicWriter<wchar_t> |
+---------+----------------------+
\endrst
*/
template
<
typename
Char
>
class
BasicWriter
{
private
:
private
:
// Output buffer.
Buffer
<
Char
>
&
buffer_
;
...
...
@@ -1664,9 +1974,13 @@ class BasicWriter {
#if _SECURE_SCL
// Returns pointer value.
static
Char
*
get
(
CharPtr
p
)
{
return
p
.
base
();
}
static
Char
*
get
(
CharPtr
p
)
{
return
p
.
base
();
}
#else
static
Char
*
get
(
Char
*
p
)
{
return
p
;
}
static
Char
*
get
(
Char
*
p
)
{
return
p
;
}
#endif
// Fills the padding around the content and returns the pointer to the
...
...
@@ -1729,31 +2043,39 @@ class BasicWriter {
template
<
typename
T
>
void
append_float_length
(
Char
*&
,
T
)
{}
friend
class
internal
::
ArgFormatter
<
Char
>
;
friend
class
internal
::
PrintfFormatter
<
Char
>
;
template
<
typename
Impl
,
typename
Char_
>
friend
class
internal
::
BasicArgFormatter
;
protected
:
friend
class
internal
::
PrintfArgFormatter
<
Char
>
;
protected
:
/**
Constructs a ``BasicWriter`` object.
*/
explicit
BasicWriter
(
Buffer
<
Char
>
&
b
)
:
buffer_
(
b
)
{}
public
:
public
:
/**
\rst
Destroys a ``BasicWriter`` object.
\endrst
*/
virtual
~
BasicWriter
()
{}
/**
Returns the total number of characters written.
*/
std
::
size_t
size
()
const
{
return
buffer_
.
size
();
}
std
::
size_t
size
()
const
{
return
buffer_
.
size
();
}
/**
Returns a pointer to the output buffer content. No terminating null
character is appended.
*/
const
Char
*
data
()
const
FMT_NOEXCEPT
{
return
&
buffer_
[
0
];
}
const
Char
*
data
()
const
FMT_NOEXCEPT
{
return
&
buffer_
[
0
];
}
/**
Returns a pointer to the output buffer content with terminating null
...
...
@@ -1767,7 +2089,9 @@ class BasicWriter {
}
/**
\rst
Returns the content of the output buffer as an `std::string`.
\endrst
*/
std
::
basic_string
<
Char
>
str
()
const
{
return
std
::
basic_string
<
Char
>
(
&
buffer_
[
0
],
buffer_
.
size
());
...
...
@@ -1798,10 +2122,10 @@ class BasicWriter {
See also :ref:`syntax`.
\endrst
*/
void
write
(
Basic
StringRef
<
Char
>
format
,
ArgList
args
)
{
void
write
(
BasicC
StringRef
<
Char
>
format
,
ArgList
args
)
{
BasicFormatter
<
Char
>
(
*
this
).
format
(
format
,
args
);
}
FMT_VARIADIC_VOID
(
write
,
Basic
StringRef
<
Char
>
)
FMT_VARIADIC_VOID
(
write
,
BasicC
StringRef
<
Char
>
)
BasicWriter
&
operator
<<
(
int
value
)
{
return
*
this
<<
IntFormatSpec
<
int
>
(
value
);
...
...
@@ -1820,7 +2144,9 @@ class BasicWriter {
}
/**
\rst
Formats *value* and writes it to the stream.
\endrst
*/
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
return
*
this
<<
IntFormatSpec
<
ULongLong
>
(
value
);
...
...
@@ -1832,8 +2158,10 @@ class BasicWriter {
}
/**
\rst
Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream.
\endrst
*/
BasicWriter
&
operator
<<
(
long
double
value
)
{
write_double
(
value
,
FormatSpec
());
...
...
@@ -1855,10 +2183,19 @@ class BasicWriter {
}
/**
\rst
Writes *value* to the stream.
\endrst
*/
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
const
Char
*
str
=
value
.
c_str
();
const
Char
*
str
=
value
.
data
();
buffer_
.
append
(
str
,
str
+
value
.
size
());
return
*
this
;
}
BasicWriter
&
operator
<<
(
typename
internal
::
WCharHelper
<
StringRef
,
Char
>::
Supported
value
)
{
const
char
*
str
=
value
.
data
();
buffer_
.
append
(
str
,
str
+
value
.
size
());
return
*
this
;
}
...
...
@@ -1873,12 +2210,11 @@ class BasicWriter {
template
<
typename
StrChar
>
BasicWriter
&
operator
<<
(
const
StrFormatSpec
<
StrChar
>
&
spec
)
{
const
StrChar
*
s
=
spec
.
str
();
// TODO: error if fill is not convertible to Char
write_str
(
s
,
std
::
char_traits
<
Char
>::
length
(
s
),
spec
);
return
*
this
;
}
void
clear
()
FMT_NOEXCEPT
{
buffer_
.
clear
();
}
void
clear
()
FMT_NOEXCEPT
{
buffer_
.
clear
();
}
};
template
<
typename
Char
>
...
...
@@ -1888,16 +2224,19 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
CharPtr
out
=
CharPtr
();
if
(
spec
.
width
()
>
size
)
{
out
=
grow_buffer
(
spec
.
width
());
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
if
(
spec
.
align
()
==
ALIGN_RIGHT
)
{
std
::
fill_n
(
out
,
spec
.
width
()
-
size
,
fill
);
out
+=
spec
.
width
()
-
size
;
}
else
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
}
else
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
out
=
fill_padding
(
out
,
spec
.
width
(),
size
,
fill
);
}
else
{
}
else
{
std
::
fill_n
(
out
+
size
,
spec
.
width
()
-
size
,
fill
);
}
}
else
{
}
else
{
out
=
grow_buffer
(
size
);
}
std
::
copy
(
s
,
s
+
size
,
out
);
...
...
@@ -1906,12 +2245,12 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
template
<
typename
Char
>
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
fill_padding
(
BasicWriter
<
Char
>::
fill_padding
(
CharPtr
buffer
,
unsigned
total_size
,
std
::
size_t
content_size
,
wchar_t
fill
)
{
std
::
size_t
padding
=
total_size
-
content_size
;
std
::
size_t
left_padding
=
padding
/
2
;
Char
fill_char
=
static_cast
<
Char
>
(
fill
);
Char
fill_char
=
internal
::
CharTraits
<
Char
>::
cast
(
fill
);
std
::
fill_n
(
buffer
,
left_padding
,
fill_char
);
buffer
+=
left_padding
;
CharPtr
content
=
buffer
;
...
...
@@ -1922,12 +2261,12 @@ typename BasicWriter<Char>::CharPtr
template
<
typename
Char
>
template
<
typename
Spec
>
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
prepare_int_buffer
(
BasicWriter
<
Char
>::
prepare_int_buffer
(
unsigned
num_digits
,
const
Spec
&
spec
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
unsigned
width
=
spec
.
width
();
Alignment
align
=
spec
.
align
();
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
if
(
spec
.
precision
()
>
static_cast
<
int
>
(
num_digits
))
{
// Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified.
...
...
@@ -1963,17 +2302,20 @@ typename BasicWriter<Char>::CharPtr
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
+=
size
;
std
::
fill
(
p
,
end
,
fill
);
}
else
if
(
align
==
ALIGN_CENTER
)
{
}
else
if
(
align
==
ALIGN_CENTER
)
{
p
=
fill_padding
(
p
,
width
,
size
,
fill
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
+=
size
;
}
else
{
}
else
{
if
(
align
==
ALIGN_NUMERIC
)
{
if
(
prefix_size
!=
0
)
{
p
=
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
size
-=
prefix_size
;
}
}
else
{
}
else
{
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
end
-
size
);
}
std
::
fill
(
p
,
end
-
size
,
fill
);
...
...
@@ -1993,19 +2335,22 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
prefix
[
0
]
=
'-'
;
++
prefix_size
;
abs_value
=
0
-
abs_value
;
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
prefix
[
0
]
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
++
prefix_size
;
}
switch
(
spec
.
type
())
{
case
0
:
case
'd'
:
{
case
0
:
case
'd'
:
{
unsigned
num_digits
=
internal
::
count_digits
(
abs_value
);
CharPtr
p
=
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
)
+
1
-
num_digits
;
internal
::
format_decimal
(
get
(
p
),
abs_value
,
num_digits
);
break
;
}
case
'x'
:
case
'X'
:
{
case
'x'
:
case
'X'
:
{
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
...
...
@@ -2025,7 +2370,8 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
}
while
((
n
>>=
4
)
!=
0
);
break
;
}
case
'b'
:
case
'B'
:
{
case
'b'
:
case
'B'
:
{
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
...
...
@@ -2075,7 +2421,10 @@ void BasicWriter<Char>::write_double(
case
0
:
type
=
'g'
;
break
;
case
'e'
:
case
'f'
:
case
'g'
:
case
'a'
:
case
'e'
:
case
'f'
:
case
'g'
:
case
'a'
:
break
;
case
'F'
:
#ifdef _MSC_VER
...
...
@@ -2083,7 +2432,9 @@ void BasicWriter<Char>::write_double(
type
=
'f'
;
#endif
// Fall through.
case
'E'
:
case
'G'
:
case
'A'
:
case
'E'
:
case
'G'
:
case
'A'
:
upper
=
true
;
break
;
default
:
...
...
@@ -2097,7 +2448,8 @@ void BasicWriter<Char>::write_double(
if
(
internal
::
getsign
(
static_cast
<
double
>
(
value
)))
{
sign
=
'-'
;
value
=
-
value
;
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
}
...
...
@@ -2141,7 +2493,7 @@ void BasicWriter<Char>::write_double(
}
// Build format string.
enum
{
MAX_FORMAT_SIZE
=
10
};
// longest format: %#-*.*Lg
enum
{
MAX_FORMAT_SIZE
=
10
};
// longest format: %#-*.*Lg
Char
format
[
MAX_FORMAT_SIZE
];
Char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
...
...
@@ -2150,7 +2502,8 @@ void BasicWriter<Char>::write_double(
*
format_ptr
++
=
'#'
;
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
width_for_sprintf
=
0
;
}
else
{
}
else
{
if
(
spec
.
align
()
==
ALIGN_LEFT
)
*
format_ptr
++
=
'-'
;
if
(
width
!=
0
)
...
...
@@ -2166,7 +2519,7 @@ void BasicWriter<Char>::write_double(
*
format_ptr
=
'\0'
;
// Format using snprintf.
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
Char
fill
=
internal
::
CharTraits
<
Char
>::
cast
(
spec
.
fill
());
for
(;;)
{
std
::
size_t
buffer_size
=
buffer_
.
capacity
()
-
offset
;
#if _MSC_VER
...
...
@@ -2187,7 +2540,8 @@ void BasicWriter<Char>::write_double(
*
start
!=
' '
)
{
*
(
start
-
1
)
=
sign
;
sign
=
0
;
}
else
{
}
else
{
*
(
start
-
1
)
=
fill
;
}
++
n
;
...
...
@@ -2216,45 +2570,45 @@ void BasicWriter<Char>::write_double(
}
/**
\rst
This class template provides operations for formatting and writing data
into a character stream. The output is stored in a memory buffer that grows
dynamically.
\rst
This class template provides operations for formatting and writing data
into a character stream. The output is stored in a memory buffer that grows
dynamically.
You can use one of the following typedefs for common character types
and the standard allocator:
You can use one of the following typedefs for common character types
and the standard allocator:
+---------------+-----------------------------------------------------+
| Type | Definition |
+===============+=====================================================+
| MemoryWriter | BasicMemoryWriter<char, std::allocator<char>> |
+---------------+-----------------------------------------------------+
| WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> |
+---------------+-----------------------------------------------------+
+---------------+-----------------------------------------------------+
| Type | Definition |
+===============+=====================================================+
| MemoryWriter | BasicMemoryWriter<char, std::allocator<char>> |
+---------------+-----------------------------------------------------+
| WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> |
+---------------+-----------------------------------------------------+
**Example**::
**Example**::
MemoryWriter out;
out << "The answer is " << 42 << "\n";
out.write("({:+f}, {:+f})", -3.14, 3.14);
MemoryWriter out;
out << "The answer is " << 42 << "\n";
out.write("({:+f}, {:+f})", -3.14, 3.14);
This will write the following output to the ``out`` object:
This will write the following output to the ``out`` object:
.. code-block:: none
.. code-block:: none
The answer is 42
(-3.140000, +3.140000)
The answer is 42
(-3.140000, +3.140000)
The output can be converted to an ``std::string`` with ``out.str()`` or
accessed as a C string with ``out.c_str()``.
\endrst
*/
The output can be converted to an ``std::string`` with ``out.str()`` or
accessed as a C string with ``out.c_str()``.
\endrst
*/
template
<
typename
Char
,
typename
Allocator
=
std
::
allocator
<
Char
>
>
class
BasicMemoryWriter
:
public
BasicWriter
<
Char
>
{
private
:
private
:
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
,
Allocator
>
buffer_
;
public
:
public
:
explicit
BasicMemoryWriter
(
const
Allocator
&
alloc
=
Allocator
())
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
alloc
)
{}
...
...
@@ -2285,31 +2639,31 @@ typedef BasicMemoryWriter<char> MemoryWriter;
typedef
BasicMemoryWriter
<
wchar_t
>
WMemoryWriter
;
/**
\rst
This class template provides operations for formatting and writing data
into a fixed-size array. For writing into a dynamically growing buffer
use :class:`fmt::BasicMemoryWriter`.
Any write method will throw ``std::runtime_error`` if the output doesn't fit
into the array.
You can use one of the following typedefs for common character types:
+--------------+---------------------------+
| Type | Definition |
+==============+===========================+
| ArrayWriter | BasicArrayWriter<char> |
+--------------+---------------------------+
| WArrayWriter | BasicArrayWriter<wchar_t> |
+--------------+---------------------------+
\endrst
*/
\rst
This class template provides operations for formatting and writing data
into a fixed-size array. For writing into a dynamically growing buffer
use :class:`fmt::BasicMemoryWriter`.
Any write method will throw ``std::runtime_error`` if the output doesn't fit
into the array.
You can use one of the following typedefs for common character types:
+--------------+---------------------------+
| Type | Definition |
+==============+===========================+
| ArrayWriter | BasicArrayWriter<char> |
+--------------+---------------------------+
| WArrayWriter | BasicArrayWriter<wchar_t> |
+--------------+---------------------------+
\endrst
*/
template
<
typename
Char
>
class
BasicArrayWriter
:
public
BasicWriter
<
Char
>
{
private
:
private
:
internal
::
FixedBuffer
<
Char
>
buffer_
;
public
:
public
:
/**
\rst
Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
...
...
@@ -2319,15 +2673,14 @@ class BasicArrayWriter : public BasicWriter<Char> {
BasicArrayWriter
(
Char
*
array
,
std
::
size_t
size
)
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
array
,
size
)
{}
// FIXME: this is temporary undocumented due to a bug in Sphinx
/*
/**
\rst
Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
size known at compile time.
\endrst
*/
template
<
std
::
size_t
SIZE
>
explicit
BasicArrayWriter
(
Char
(
&
array
)[
SIZE
])
explicit
BasicArrayWriter
(
Char
(
&
array
)[
SIZE
])
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
array
,
SIZE
)
{}
};
...
...
@@ -2350,14 +2703,14 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
// Can be used to report errors from destructors.
void
report_system_error
(
int
error_code
,
StringRef
message
)
FMT_NOEXCEPT
;
#if
def _WIN32
#if
FMT_USE_WINDOWS_H
/** A Windows error. */
class
WindowsError
:
public
SystemError
{
private
:
void
init
(
int
error_code
,
StringRef
format_str
,
ArgList
args
);
private
:
void
init
(
int
error_code
,
C
StringRef
format_str
,
ArgList
args
);
public
:
public
:
/**
\rst
Constructs a :class:`fmt::WindowsError` object with the description
...
...
@@ -2386,10 +2739,10 @@ class WindowsError : public SystemError {
}
\endrst
*/
WindowsError
(
int
error_code
,
StringRef
message
)
{
WindowsError
(
int
error_code
,
C
StringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
}
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
StringRef
)
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
C
StringRef
)
};
// Reports a Windows error without throwing an exception.
...
...
@@ -2401,119 +2754,119 @@ void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
enum
Color
{
BLACK
,
RED
,
GREEN
,
YELLOW
,
BLUE
,
MAGENTA
,
CYAN
,
WHITE
};
/**
Formats a string and prints it to stdout using ANSI escape sequences
to specify color (experimental).
Example:
PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
*/
void
print_colored
(
Color
c
,
StringRef
format
,
ArgList
args
);
Formats a string and prints it to stdout using ANSI escape sequences
to specify color (experimental).
Example:
PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
*/
void
print_colored
(
Color
c
,
C
StringRef
format
,
ArgList
args
);
/**
\rst
Formats arguments and returns the result as a string.
\rst
Formats arguments and returns the result as a string.
**Example**::
**Example**::
std::string message = format("The answer is {}", 42);
\endrst
std::string message = format("The answer is {}", 42);
\endrst
*/
inline
std
::
string
format
(
StringRef
format_str
,
ArgList
args
)
{
inline
std
::
string
format
(
C
StringRef
format_str
,
ArgList
args
)
{
MemoryWriter
w
;
w
.
write
(
format_str
,
args
);
return
w
.
str
();
}
inline
std
::
wstring
format
(
WStringRef
format_str
,
ArgList
args
)
{
inline
std
::
wstring
format
(
W
C
StringRef
format_str
,
ArgList
args
)
{
WMemoryWriter
w
;
w
.
write
(
format_str
,
args
);
return
w
.
str
();
}
/**
\rst
Prints formatted data to the file *f*.
\rst
Prints formatted data to the file *f*.
**Example**::
**Example**::
print(stderr, "Don't {}!", "panic");
\endrst
*/
void
print
(
std
::
FILE
*
f
,
StringRef
format_str
,
ArgList
args
);
print(stderr, "Don't {}!", "panic");
\endrst
*/
void
print
(
std
::
FILE
*
f
,
C
StringRef
format_str
,
ArgList
args
);
/**
\rst
Prints formatted data to ``stdout``.
\rst
Prints formatted data to ``stdout``.
**Example**::
**Example**::
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
void
print
(
StringRef
format_str
,
ArgList
args
);
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
void
print
(
C
StringRef
format_str
,
ArgList
args
);
/**
\rst
Prints formatted data to the stream *os*.
\rst
Prints formatted data to the stream *os*.
**Example**::
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
void
print
(
std
::
ostream
&
os
,
StringRef
format_str
,
ArgList
args
);
print(cerr, "Don't {}!", "panic");
\endrst
*/
void
print
(
std
::
ostream
&
os
,
C
StringRef
format_str
,
ArgList
args
);
template
<
typename
Char
>
void
printf
(
BasicWriter
<
Char
>
&
w
,
BasicStringRef
<
Char
>
format
,
ArgList
args
)
{
void
printf
(
BasicWriter
<
Char
>
&
w
,
Basic
C
StringRef
<
Char
>
format
,
ArgList
args
)
{
internal
::
PrintfFormatter
<
Char
>
().
format
(
w
,
format
,
args
);
}
/**
\rst
Formats arguments and returns the result as a string.
\rst
Formats arguments and returns the result as a string.
**Example**::
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
inline
std
::
string
sprintf
(
StringRef
format
,
ArgList
args
)
{
inline
std
::
string
sprintf
(
C
StringRef
format
,
ArgList
args
)
{
MemoryWriter
w
;
printf
(
w
,
format
,
args
);
return
w
.
str
();
}
/**
\rst
Prints formatted data to the file *f*.
\rst
Prints formatted data to the file *f*.
**Example**::
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
int
fprintf
(
std
::
FILE
*
f
,
StringRef
format
,
ArgList
args
);
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
int
fprintf
(
std
::
FILE
*
f
,
C
StringRef
format
,
ArgList
args
);
/**
\rst
Prints formatted data to ``stdout``.
\rst
Prints formatted data to ``stdout``.
**Example**::
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline
int
printf
(
StringRef
format
,
ArgList
args
)
{
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline
int
printf
(
C
StringRef
format
,
ArgList
args
)
{
return
fprintf
(
stdout
,
format
,
args
);
}
/**
Fast integer formatter.
*/
Fast integer formatter.
*/
class
FormatInt
{
private
:
private
:
// Buffer should be large enough to hold all digits (digits10 + 1),
// a sign and a null character.
enum
{
BUFFER_SIZE
=
std
::
numeric_limits
<
ULongLong
>::
digits10
+
3
};
enum
{
BUFFER_SIZE
=
std
::
numeric_limits
<
ULongLong
>::
digits10
+
3
};
mutable
char
buffer_
[
BUFFER_SIZE
];
char
*
str_
;
...
...
@@ -2549,10 +2902,16 @@ class FormatInt {
*--
str_
=
'-'
;
}
public
:
explicit
FormatInt
(
int
value
)
{
FormatSigned
(
value
);
}
explicit
FormatInt
(
long
value
)
{
FormatSigned
(
value
);
}
explicit
FormatInt
(
LongLong
value
)
{
FormatSigned
(
value
);
}
public
:
explicit
FormatInt
(
int
value
)
{
FormatSigned
(
value
);
}
explicit
FormatInt
(
long
value
)
{
FormatSigned
(
value
);
}
explicit
FormatInt
(
LongLong
value
)
{
FormatSigned
(
value
);
}
explicit
FormatInt
(
unsigned
value
)
:
str_
(
format_decimal
(
value
))
{}
explicit
FormatInt
(
unsigned
long
value
)
:
str_
(
format_decimal
(
value
))
{}
explicit
FormatInt
(
ULongLong
value
)
:
str_
(
format_decimal
(
value
))
{}
...
...
@@ -2560,13 +2919,17 @@ class FormatInt {
/**
Returns the number of characters written to the output buffer.
*/
std
::
size_t
size
()
const
{
return
buffer_
-
str_
+
BUFFER_SIZE
-
1
;
}
std
::
size_t
size
()
const
{
return
buffer_
-
str_
+
BUFFER_SIZE
-
1
;
}
/**
Returns a pointer to the output buffer content. No terminating null
character is appended.
*/
const
char
*
data
()
const
{
return
str_
;
}
const
char
*
data
()
const
{
return
str_
;
}
/**
Returns a pointer to the output buffer content with terminating null
...
...
@@ -2578,9 +2941,13 @@ class FormatInt {
}
/**
Returns the content of the output buffer as an `std::string`.
\rst
Returns the content of the output buffer as an ``std::string``.
\endrst
*/
std
::
string
str
()
const
{
return
std
::
string
(
str_
,
size
());
}
std
::
string
str
()
const
{
return
std
::
string
(
str_
,
size
());
}
};
// Formats a decimal integer value writing into buffer and returns
...
...
@@ -2607,6 +2974,33 @@ inline void format_decimal(char *&buffer, T value) {
internal
::
format_decimal
(
buffer
,
abs_value
,
num_digits
);
buffer
+=
num_digits
;
}
/**
\rst
Returns a named argument for formatting functions.
**Example**::
print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
\endrst
*/
template
<
typename
T
>
inline
internal
::
NamedArg
<
char
>
arg
(
StringRef
name
,
const
T
&
arg
)
{
return
internal
::
NamedArg
<
char
>
(
name
,
arg
);
}
template
<
typename
T
>
inline
internal
::
NamedArg
<
wchar_t
>
arg
(
WStringRef
name
,
const
T
&
arg
)
{
return
internal
::
NamedArg
<
wchar_t
>
(
name
,
arg
);
}
// The following two functions are deleted intentionally to disable
// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``.
template
<
typename
Char
>
void
arg
(
StringRef
,
const
internal
::
NamedArg
<
Char
>&
)
FMT_DELETED_OR_UNDEFINED
;
template
<
typename
Char
>
void
arg
(
WStringRef
,
const
internal
::
NamedArg
<
Char
>&
)
FMT_DELETED_OR_UNDEFINED
;
}
#if FMT_GCC_VERSION
...
...
@@ -2637,52 +3031,13 @@ inline void format_decimal(char *&buffer, T value) {
#define FMT_GET_ARG_NAME(type, index) arg##index
#if FMT_USE_VARIADIC_TEMPLATES
namespace
fmt
{
namespace
internal
{
inline
void
do_set_types
(
Arg
*
)
{}
template
<
typename
T
,
typename
...
Args
>
inline
void
do_set_types
(
Arg
*
args
,
const
T
&
arg
,
const
Args
&
...
tail
)
{
args
->
type
=
static_cast
<
Arg
::
Type
>
(
MakeValue
<
T
>::
type
(
arg
));
do_set_types
(
args
+
1
,
tail
...);
}
template
<
typename
...
Args
>
inline
void
set_types
(
Arg
*
array
,
const
Args
&
...
args
)
{
do_set_types
(
array
,
args
...);
array
[
sizeof
...(
Args
)].
type
=
Arg
::
NONE
;
}
template
<
typename
...
Args
>
inline
void
set_types
(
Value
*
,
const
Args
&
...)
{
// Do nothing as types are passed separately from values.
}
// Computes the argument array size by adding 1 to N, which is the number of
// arguments, if N is zero, because array of zero size is invalid, or if N
// is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
// argument that marks the end of the list.
template
<
unsigned
N
>
struct
ArgArraySize
{
enum
{
VALUE
=
N
+
(
N
==
0
||
N
>
ArgList
::
MAX_PACKED_ARGS
?
1
:
0
)
};
};
}
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
template <typename... Args> \
ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const Args & ... args) { \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
Value array[internal::ArgArraySize<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
if (internal::check((sizeof...(Args) > fmt::ArgList::MAX_PACKED_ARGS))) \
set_types(array, args...); \
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::
ArgList(internal::make_type(args...), array
)); \
fmt::
internal::make_arg_list<Char>(array, args...
)); \
}
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
...
...
@@ -2691,9 +3046,9 @@ struct ArgArraySize {
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::Value values[]
= {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \
fmt::internal::ArgArray<n>::Type arr
= {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)),
values
)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)),
arr
)); \
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
...
...
@@ -2718,48 +3073,70 @@ struct ArgArraySize {
#endif // FMT_USE_VARIADIC_TEMPLATES
/**
\rst
Defines a variadic function with the specified return type, function name
and argument types passed as variable arguments to this macro.
\rst
Defines a variadic function with the specified return type, function name
and argument types passed as variable arguments to this macro.
**Example**::
**Example**::
void print_error(const char *file, int line, const char *format,
fmt::ArgList args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args);
}
FMT_VARIADIC(void, print_error, const char *, int, const char *)
void print_error(const char *file, int line, const char *format,
fmt::ArgList args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args);
}
FMT_VARIADIC(void, print_error, const char *, int, const char *)
``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that
don't implement variadic templates. You don't have to use this macro if
you don't need legacy compiler support and can use variadic templates
directly::
``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that
don't implement variadic templates. You don't have to use this macro if
you don't need legacy compiler support and can use variadic templates
directly::
template <typename... Args>
void print_error(const char *file, int line, const char *format,
const Args & ... args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args...);
}
\endrst
*/
template <typename... Args>
void print_error(const char *file, int line, const char *format,
const Args & ... args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args...);
}
\endrst
*/
#define FMT_VARIADIC(ReturnType, func, ...) \
FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_W(ReturnType, func, ...) \
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__)
#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id)
#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id)
/**
\rst
Convenient macro to capture the arguments' names and values into several
``fmt::arg(name, value)``.
**Example**::
int x = 1, y = 2;
print("point: ({x}, {y})", FMT_CAPTURE(x, y));
// same as:
// print("point: ({x}, {y})", arg("x", x), arg("y", y));
\endrst
*/
#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__)
#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__)
namespace
fmt
{
FMT_VARIADIC
(
std
::
string
,
format
,
StringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
WStringRef
)
FMT_VARIADIC
(
void
,
print
,
StringRef
)
FMT_VARIADIC
(
void
,
print
,
std
::
FILE
*
,
StringRef
)
FMT_VARIADIC
(
void
,
print
,
std
::
ostream
&
,
StringRef
)
FMT_VARIADIC
(
void
,
print_colored
,
Color
,
StringRef
)
FMT_VARIADIC
(
std
::
string
,
sprintf
,
StringRef
)
FMT_VARIADIC
(
int
,
printf
,
StringRef
)
FMT_VARIADIC
(
int
,
fprintf
,
std
::
FILE
*
,
StringRef
)
FMT_VARIADIC
(
std
::
string
,
format
,
C
StringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
W
C
StringRef
)
FMT_VARIADIC
(
void
,
print
,
C
StringRef
)
FMT_VARIADIC
(
void
,
print
,
std
::
FILE
*
,
C
StringRef
)
FMT_VARIADIC
(
void
,
print
,
std
::
ostream
&
,
C
StringRef
)
FMT_VARIADIC
(
void
,
print_colored
,
Color
,
C
StringRef
)
FMT_VARIADIC
(
std
::
string
,
sprintf
,
C
StringRef
)
FMT_VARIADIC
(
int
,
printf
,
C
StringRef
)
FMT_VARIADIC
(
int
,
fprintf
,
std
::
FILE
*
,
C
StringRef
)
}
// Restore warnings.
...
...
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