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
06e0b038
Commit
06e0b038
authored
Apr 27, 2015
by
gabime
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://github.com/gabime/spdlog
parents
285a47de
80fcd655
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
940 additions
and
1150 deletions
+940
-1150
format.cc
include/spdlog/details/format.cc
+163
-140
format.h
include/spdlog/details/format.h
+777
-1010
No files found.
include/spdlog/details/format.cc
View file @
06e0b038
/*
Formatting library for C++
Copyright (c) 2012 - 2014
, 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"
...
...
@@ -66,10 +66,8 @@ using fmt::internal::Arg;
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# define FMT_THROW(x) throw x
# define FMT_RETURN_AFTER_THROW(x)
# else
# define FMT_THROW(x) assert(false)
# define FMT_RETURN_AFTER_THROW(x) return x
# endif
#endif
...
...
@@ -83,8 +81,20 @@ using fmt::internal::Arg;
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
static
inline
fmt
::
internal
::
None
<>
strerror_r
(
int
,
char
*
,
...)
{
return
fmt
::
internal
::
None
<>
();
}
static
inline
fmt
::
internal
::
None
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
fmt
::
internal
::
None
<>
();
}
namespace
{
#ifndef _MSC_VER
...
...
@@ -100,6 +110,12 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template
<
bool
IsSigned
>
...
...
@@ -121,7 +137,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.
...
...
@@ -133,59 +149,81 @@ 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
{
int
error_code
,
char
*&
buffer
,
std
::
size_t
buffer_size
)
FMT_NOEXCEPT
{
assert
(
buffer
!=
0
&&
buffer_size
!=
0
);
int
result
=
0
;
#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__
// XSI-compliant version of strerror_r.
result
=
strerror_r
(
error_code
,
buffer
,
buffer_size
);
if
(
result
!=
0
)
result
=
errno
;
#elif _GNU_SOURCE
// GNU-specific version of strerror_r.
char
*
message
=
strerror_r
(
error_code
,
buffer
,
buffer_size
);
class
StrError
{
private
:
int
error_code_
;
char
*&
buffer_
;
std
::
size_t
buffer_size_
;
// A noop assignment operator to avoid bogus warnings.
void
operator
=
(
const
StrError
&
)
{}
// Handle the result of XSI-compliant version of strerror_r.
int
handle
(
int
result
)
{
// glibc versions before 2.13 return result in errno.
return
result
==
-
1
?
errno
:
result
;
}
// Handle the result of GNU-specific version of strerror_r.
int
handle
(
char
*
message
)
{
// If the buffer is full then the message is probably truncated.
if
(
message
==
buffer
&&
strlen
(
buffer
)
==
buffer_size
-
1
)
result
=
ERANGE
;
buffer
=
message
;
#elif __MINGW32__
errno
=
0
;
(
void
)
buffer_size
;
buffer
=
strerror
(
error_code
);
result
=
errno
;
#elif _WIN32
result
=
strerror_s
(
buffer
,
buffer_size
,
error_code
);
if
(
message
==
buffer_
&&
strlen
(
buffer_
)
==
buffer_size_
-
1
)
return
ERANGE
;
buffer_
=
message
;
return
0
;
}
// Handle the case when strerror_r is not available.
int
handle
(
fmt
::
internal
::
None
<>
)
{
return
fallback
(
strerror_s
(
buffer_
,
buffer_size_
,
error_code_
));
}
// Fallback to strerror_s when strerror_r is not available.
int
fallback
(
int
result
)
{
// If the buffer is full then the message is probably truncated.
if
(
result
==
0
&&
std
::
strlen
(
buffer
)
==
buffer_size
-
1
)
result
=
ERANGE
;
#else
result
=
strerror_r
(
error_code
,
buffer
,
buffer_size
);
if
(
result
==
-
1
)
result
=
errno
;
// glibc versions before 2.13 return result in errno.
#endif
return
result
;
return
result
==
0
&&
strlen
(
buffer_
)
==
buffer_size_
-
1
?
ERANGE
:
result
;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int
fallback
(
fmt
::
internal
::
None
<>
)
{
errno
=
0
;
buffer_
=
strerror
(
error_code_
);
return
errno
;
}
public
:
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_
));
}
};
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.
out
.
clear
();
static
const
char
SEP
[]
=
": "
;
static
const
char
ER
R
[]
=
"error "
;
static
const
char
ERROR_ST
R
[]
=
"error "
;
fmt
::
internal
::
IntTraits
<
int
>::
MainType
ec_value
=
error_code
;
// Subtract 2 to account for terminating null characters in SEP and ER
R.
std
::
size_t
error_code_size
=
sizeof
(
SEP
)
+
sizeof
(
ERR
)
+
fmt
::
internal
::
count_digits
(
ec_value
)
-
2
;
// Subtract 2 to account for terminating null characters in SEP and ERROR_ST
R.
std
::
size_t
error_code_size
=
sizeof
(
SEP
)
+
sizeof
(
ERROR_STR
)
-
2
;
error_code_size
+=
fmt
::
internal
::
count_digits
(
ec_value
)
;
if
(
message
.
size
()
<=
fmt
::
internal
::
INLINE_BUFFER_SIZE
-
error_code_size
)
out
<<
message
<<
SEP
;
out
<<
ER
R
<<
error_code
;
out
<<
ERROR_ST
R
<<
error_code
;
assert
(
out
.
size
()
<=
fmt
::
internal
::
INLINE_BUFFER_SIZE
);
}
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
...
...
@@ -196,11 +234,9 @@ 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.
...
...
@@ -245,17 +281,16 @@ 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
)
{}
unsigned
visi
t_unhandled_arg
()
{
void
repor
t_unhandled_arg
()
{
FMT_THROW
(
fmt
::
FormatError
(
"width is not integer"
));
FMT_RETURN_AFTER_THROW
(
0
);
}
template
<
typename
T
>
...
...
@@ -274,10 +309,9 @@ public:
class
PrecisionHandler
:
public
fmt
::
internal
::
ArgVisitor
<
PrecisionHandler
,
int
>
{
public
:
unsigned
visi
t_unhandled_arg
()
{
public
:
void
repor
t_unhandled_arg
()
{
FMT_THROW
(
fmt
::
FormatError
(
"precision is not integer"
));
FMT_RETURN_AFTER_THROW
(
0
);
}
template
<
typename
T
>
...
...
@@ -291,13 +325,13 @@ public:
// 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
)
{}
...
...
@@ -310,20 +344,17 @@ public:
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
);
...
...
@@ -334,12 +365,12 @@ public:
// 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
>
...
...
@@ -357,15 +388,11 @@ Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
template
<>
inline
Arg
::
StringValue
<
char
>
ignore_incompatible_str
(
Arg
::
StringValue
<
wchar_t
>
)
{
return
Arg
::
StringValue
<
char
>
();
}
Arg
::
StringValue
<
wchar_t
>
)
{
return
Arg
::
StringValue
<
char
>
();
}
template
<>
inline
Arg
::
StringValue
<
wchar_t
>
ignore_incompatible_str
(
Arg
::
StringValue
<
wchar_t
>
s
)
{
return
s
;
}
Arg
::
StringValue
<
wchar_t
>
s
)
{
return
s
;
}
}
// namespace
FMT_FUNC
void
fmt
::
SystemError
::
init
(
...
...
@@ -397,12 +424,12 @@ int fmt::internal::CharTraits<wchar_t>::format_float(
unsigned
width
,
int
precision
,
T
value
)
{
if
(
width
==
0
)
{
return
precision
<
0
?
swprintf
(
buffer
,
size
,
format
,
value
)
:
swprintf
(
buffer
,
size
,
format
,
precision
,
value
);
FMT_SWPRINTF
(
buffer
,
size
,
format
,
value
)
:
FMT_SWPRINTF
(
buffer
,
size
,
format
,
precision
,
value
);
}
return
precision
<
0
?
swprintf
(
buffer
,
size
,
format
,
width
,
value
)
:
swprintf
(
buffer
,
size
,
format
,
width
,
precision
,
value
);
FMT_SWPRINTF
(
buffer
,
size
,
format
,
width
,
value
)
:
FMT_SWPRINTF
(
buffer
,
size
,
format
,
width
,
precision
,
value
);
}
template
<
typename
T
>
...
...
@@ -440,6 +467,7 @@ const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
};
FMT_FUNC
void
fmt
::
internal
::
report_unknown_type
(
char
code
,
const
char
*
type
)
{
(
void
)
type
;
if
(
std
::
isprint
(
static_cast
<
unsigned
char
>
(
code
)))
{
FMT_THROW
(
fmt
::
FormatError
(
fmt
::
format
(
"unknown format code '{}' for {}"
,
code
,
type
)));
...
...
@@ -496,8 +524,8 @@ FMT_FUNC void fmt::WindowsError::init(
FMT_FUNC
void
fmt
::
internal
::
format_system_error
(
fmt
::
Writer
&
out
,
int
error_code
,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
fmt
::
StringRef
message
)
FMT_NOEXCEPT
{
FMT_TRY
{
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer
;
buffer
.
resize
(
INLINE_BUFFER_SIZE
);
for
(;;)
{
...
...
@@ -518,22 +546,18 @@ FMT_FUNC void fmt::internal::format_system_error(
#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
,
...
...
@@ -554,7 +578,7 @@ FMT_FUNC void fmt::internal::format_windows_error(
template
<
typename
Char
>
class
fmt
::
internal
::
ArgFormatter
:
public
fmt
::
internal
::
ArgVisitor
<
fmt
::
internal
::
ArgFormatter
<
Char
>
,
void
>
{
private
:
private
:
fmt
::
BasicFormatter
<
Char
>
&
formatter_
;
fmt
::
BasicWriter
<
Char
>
&
writer_
;
fmt
::
FormatSpec
&
spec_
;
...
...
@@ -562,20 +586,16 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgFormatter
);
public
:
public
:
ArgFormatter
(
fmt
::
BasicFormatter
<
Char
>
&
f
,
fmt
::
FormatSpec
&
s
,
const
Char
*
fmt
)
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_
);
}
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_any_double
(
T
value
)
{
writer_
.
write_double
(
value
,
spec_
);
}
void
visit_char
(
int
value
)
{
if
(
spec_
.
type_
&&
spec_
.
type_
!=
'c'
)
{
...
...
@@ -597,15 +617,12 @@ public:
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
)
{
}
else
if
(
spec_
.
align_
==
fmt
::
ALIGN_CENTER
)
{
out
=
writer_
.
fill_padding
(
out
,
spec_
.
width_
,
1
,
fill
);
}
else
{
}
else
{
std
::
fill_n
(
out
+
1
,
spec_
.
width_
-
1
,
fill
);
}
}
else
{
}
else
{
out
=
writer_
.
grow_buffer
(
1
);
}
*
out
=
static_cast
<
Char
>
(
value
);
...
...
@@ -631,6 +648,11 @@ public:
}
};
template
<
typename
Char
>
void
fmt
::
internal
::
FixedBuffer
<
Char
>::
grow
(
std
::
size_t
)
{
FMT_THROW
(
std
::
runtime_error
(
"buffer overflow"
));
}
template
<
typename
Char
>
template
<
typename
StrChar
>
void
fmt
::
BasicWriter
<
Char
>::
write_str
(
...
...
@@ -720,6 +742,7 @@ void fmt::internal::PrintfFormatter<Char>::parse_flags(
template
<
typename
Char
>
Arg
fmt
::
internal
::
PrintfFormatter
<
Char
>::
get_arg
(
const
Char
*
s
,
unsigned
arg_index
)
{
(
void
)
s
;
const
char
*
error
=
0
;
Arg
arg
=
arg_index
==
UINT_MAX
?
next_arg
(
error
)
:
FormatterBase
::
get_arg
(
arg_index
-
1
,
error
);
...
...
@@ -740,8 +763,7 @@ 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
)
{
...
...
@@ -756,8 +778,7 @@ 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
));
}
...
...
@@ -792,8 +813,7 @@ 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
));
}
...
...
@@ -848,8 +868,7 @@ 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'
:
...
...
@@ -886,12 +905,10 @@ void fmt::internal::PrintfFormatter<Char>::format(
if
(
spec
.
align_
!=
ALIGN_LEFT
)
{
std
::
fill_n
(
out
,
spec
.
width_
-
1
,
fill
);
out
+=
spec
.
width_
-
1
;
}
else
{
}
else
{
std
::
fill_n
(
out
+
1
,
spec
.
width_
-
1
,
fill
);
}
}
else
{
}
else
{
out
=
writer
.
grow_buffer
(
1
);
}
*
out
=
static_cast
<
Char
>
(
arg
.
int_value
);
...
...
@@ -916,7 +933,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
case
Arg
:
:
POINTER
:
if
(
spec
.
type_
&&
spec
.
type_
!=
'p'
)
internal
::
report_unknown_type
(
spec
.
type_
,
"pointer"
);
spec
.
flags_
=
HASH_FLAG
;
spec
.
flags_
=
HASH_FLAG
;
spec
.
type_
=
'x'
;
writer
.
write_int
(
reinterpret_cast
<
uintptr_t
>
(
arg
.
pointer
),
spec
);
break
;
...
...
@@ -972,8 +989,7 @@ 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
;
...
...
@@ -1021,8 +1037,7 @@ 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
);
if
(
*
s
++
!=
'}'
)
...
...
@@ -1051,8 +1066,7 @@ 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
)
{
...
...
@@ -1099,13 +1113,13 @@ void fmt::BasicFormatter<Char>::format(
}
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
);
}
#ifdef _WIN32
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
...
...
@@ -1141,8 +1155,12 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
return
std
::
fwrite
(
w
.
data
(),
1
,
size
,
f
)
<
size
?
-
1
:
static_cast
<
int
>
(
size
);
}
#ifndef FMT_HEADER_ONLY
// Explicit instantiations for char.
template
void
fmt
::
internal
::
FixedBuffer
<
char
>::
grow
(
std
::
size_t
);
template
const
char
*
fmt
::
BasicFormatter
<
char
>::
format
(
const
char
*&
format_str
,
const
fmt
::
internal
::
Arg
&
arg
);
...
...
@@ -1162,6 +1180,8 @@ template int fmt::internal::CharTraits<char>::format_float(
// Explicit instantiations for wchar_t.
template
void
fmt
::
internal
::
FixedBuffer
<
wchar_t
>::
grow
(
std
::
size_t
);
template
const
wchar_t
*
fmt
::
BasicFormatter
<
wchar_t
>::
format
(
const
wchar_t
*&
format_str
,
const
fmt
::
internal
::
Arg
&
arg
);
...
...
@@ -1180,6 +1200,8 @@ template int fmt::internal::CharTraits<wchar_t>::format_float(
wchar_t
*
buffer
,
std
::
size_t
size
,
const
wchar_t
*
format
,
unsigned
width
,
int
precision
,
long
double
value
);
#endif // FMT_HEADER_ONLY
#if _MSC_VER
# pragma warning(pop)
#endif
\ No newline at end of file
include/spdlog/details/format.h
View file @
06e0b038
/*
Formatting library for C++
Copyright (c) 2012 - 2014
, 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_
...
...
@@ -49,13 +49,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef _MSC_VER
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
namespace
fmt
{
namespace
internal
{
namespace
fmt
{
namespace
internal
{
# pragma intrinsic(_BitScanReverse)
inline
uint32_t
clz
(
uint32_t
x
)
{
inline
uint32_t
clz
(
uint32_t
x
)
{
unsigned
long
r
=
0
;
_BitScanReverse
(
&
r
,
x
);
return
31
-
r
;
...
...
@@ -66,8 +63,7 @@ inline uint32_t clz(uint32_t x)
# pragma intrinsic(_BitScanReverse64)
# endif
inline
uint32_t
clzll
(
uint64_t
x
)
{
inline
uint32_t
clzll
(
uint64_t
x
)
{
unsigned
long
r
=
0
;
# ifdef _WIN64
_BitScanReverse64
(
&
r
,
x
);
...
...
@@ -178,8 +174,7 @@ inline uint32_t clzll(uint64_t x)
TypeName& operator=(const TypeName&)
#endif
namespace
fmt
{
namespace
fmt
{
// Fix the warning about long long on older versions of GCC
// that don't support the diagnostic pragma.
...
...
@@ -203,38 +198,37 @@ 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
:
class
BasicStringRef
{
private
:
const
Char
*
data_
;
std
::
size_t
size_
;
public
:
public
:
/**
Constructs a string reference object from a C string and a size.
*/
...
...
@@ -256,33 +250,24 @@ public:
/**
Converts a string reference to an `std::string` object.
*/
operator
std
::
basic_string
<
Char
>
()
const
{
operator
std
::
basic_string
<
Char
>
()
const
{
return
std
::
basic_string
<
Char
>
(
data_
,
size
());
}
/**
Returns the pointer to a C string.
*/
const
Char
*
c_str
()
const
{
return
data_
;
}
const
Char
*
c_str
()
const
{
return
data_
;
}
/**
Returns the string size.
*/
std
::
size_t
size
()
const
{
return
size_
;
}
std
::
size_t
size
()
const
{
return
size_
;
}
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
data_
==
rhs
.
data_
;
}
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
data_
!=
rhs
.
data_
;
}
};
...
...
@@ -291,18 +276,15 @@ typedef BasicStringRef<char> StringRef;
typedef
BasicStringRef
<
wchar_t
>
WStringRef
;
/**
A formatting error such as invalid format string.
A formatting error such as invalid format string.
*/
class
FormatError
:
public
std
::
runtime_error
{
public
:
class
FormatError
:
public
std
::
runtime_error
{
public
:
explicit
FormatError
(
StringRef
message
)
:
std
::
runtime_error
(
message
.
c_str
())
{}
};
namespace
internal
{
namespace
internal
{
// The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation.
enum
{
INLINE_BUFFER_SIZE
=
500
};
...
...
@@ -310,26 +292,22 @@ enum { INLINE_BUFFER_SIZE = 500 };
#if _SECURE_SCL
// Use checked iterator to avoid warnings on MSVC.
template
<
typename
T
>
inline
stdext
::
checked_array_iterator
<
T
*>
make_ptr
(
T
*
ptr
,
std
::
size_t
size
)
{
inline
stdext
::
checked_array_iterator
<
T
*>
make_ptr
(
T
*
ptr
,
std
::
size_t
size
)
{
return
stdext
::
checked_array_iterator
<
T
*>
(
ptr
,
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 for POD types. It supports a subset of std::vector's operations.
/
** A buffer supporting a subset of ``std::vector``'s operations. */
template
<
typename
T
>
class
Buffer
{
private
:
class
Buffer
{
private
:
FMT_DISALLOW_COPY_AND_ASSIGN
(
Buffer
);
protected
:
protected
:
T
*
ptr_
;
std
::
size_t
size_
;
std
::
size_t
capacity_
;
...
...
@@ -337,112 +315,95 @@ protected:
Buffer
(
T
*
ptr
=
0
,
std
::
size_t
capacity
=
0
)
:
ptr_
(
ptr
),
size_
(
0
),
capacity_
(
capacity
)
{}
/**
Increases the buffer capacity to hold at least *size* elements updating
``ptr_`` and ``capacity_``.
*/
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_
;
}
/** Returns the size of this buffer. */
std
::
size_t
size
()
const
{
return
size_
;
}
// Returns the capacity of this buffer.
std
::
size_t
capacity
()
const
{
return
capacity_
;
}
/** Returns the capacity of this buffer. */
std
::
size_t
capacity
()
const
{
return
capacity_
;
}
// Resizes the buffer. If T is a POD type new elements are not initialized.
void
resize
(
std
::
size_t
new_size
)
{
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void
resize
(
std
::
size_t
new_size
)
{
if
(
new_size
>
capacity_
)
grow
(
new_size
);
size_
=
new_size
;
}
// Reserves space to store at least capacity elements.
void
reserve
(
std
::
size_t
capacity
)
{
/** Reserves space to store at least *capacity* elements. */
void
reserve
(
std
::
size_t
capacity
)
{
if
(
capacity
>
capacity_
)
grow
(
capacity
);
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
push_back
(
const
T
&
value
)
{
void
push_back
(
const
T
&
value
)
{
if
(
size_
==
capacity_
)
grow
(
size_
+
1
);
ptr_
[
size_
++
]
=
value
;
}
// Appends data to the end of the buffer.
/** Appends data to the end of the buffer. */
void
append
(
const
T
*
begin
,
const
T
*
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
)
{
void
Buffer
<
T
>::
append
(
const
T
*
begin
,
const
T
*
end
)
{
std
::
ptrdiff_t
num_elements
=
end
-
begin
;
if
(
size_
+
num_elements
>
capacity_
)
grow
(
size_
+
num_elements
);
std
::
copy
(
begin
,
end
,
make_ptr
(
ptr_
,
capacity_
)
+
size_
);
std
::
copy
(
begin
,
end
,
internal
::
make_ptr
(
ptr_
,
capacity_
)
+
size_
);
size_
+=
num_elements
;
}
namespace
internal
{
// A memory buffer for POD types with the first SIZE elements stored in
// the object itself.
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
=
std
::
allocator
<
T
>
>
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
private
:
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
private
:
T
data_
[
SIZE
];
// Free memory allocated by the buffer.
void
free
()
{
void
free
()
{
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
)
{
void
move
(
MemoryBuffer
&
other
)
{
Allocator
&
this_alloc
=
*
this
,
&
other_alloc
=
other
;
this_alloc
=
std
::
move
(
other_alloc
);
this
->
size_
=
other
.
size_
;
this
->
capacity_
=
other
.
capacity_
;
if
(
other
.
ptr_
==
other
.
data_
)
{
if
(
other
.
ptr_
==
other
.
data_
)
{
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.
...
...
@@ -450,14 +411,12 @@ private:
}
}
public
:
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
public
:
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
move
(
other
);
}
MemoryBuffer
&
operator
=
(
MemoryBuffer
&&
other
)
{
MemoryBuffer
&
operator
=
(
MemoryBuffer
&&
other
)
{
assert
(
this
!=
&
other
);
free
();
move
(
other
);
...
...
@@ -466,15 +425,11 @@ public:
#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
>
void
MemoryBuffer
<
T
,
SIZE
,
Allocator
>::
grow
(
std
::
size_t
size
)
{
void
MemoryBuffer
<
T
,
SIZE
,
Allocator
>::
grow
(
std
::
size_t
size
)
{
std
::
size_t
new_capacity
=
(
std
::
max
)(
size
,
this
->
capacity_
+
this
->
capacity_
/
2
);
T
*
new_ptr
=
this
->
allocate
(
new_capacity
);
...
...
@@ -492,10 +447,19 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size)
this
->
deallocate
(
old_ptr
,
old_capacity
);
}
// A fixed-size buffer.
template
<
typename
Char
>
class
FixedBuffer
:
public
fmt
::
Buffer
<
Char
>
{
public
:
FixedBuffer
(
Char
*
array
,
std
::
size_t
size
)
:
fmt
::
Buffer
<
Char
>
(
array
,
size
)
{}
protected
:
void
grow
(
std
::
size_t
size
);
};
#ifndef _MSC_VER
// Portable version of signbit.
inline
int
getsign
(
double
x
)
{
inline
int
getsign
(
double
x
)
{
// When compiled in C++11 mode signbit is no longer a macro but a function
// defined in namespace std and the macro is undefined.
# ifdef signbit
...
...
@@ -507,27 +471,14 @@ 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
)
{
inline
int
getsign
(
double
value
)
{
if
(
value
<
0
)
return
1
;
if
(
value
==
value
)
return
0
;
int
dec
=
0
,
sign
=
0
;
...
...
@@ -535,20 +486,13 @@ 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
:
class
BasicCharTraits
{
public
:
#if _SECURE_SCL
typedef
stdext
::
checked_array_iterator
<
Char
*>
CharPtr
;
#else
...
...
@@ -560,17 +504,13 @@ template <typename Char>
class
CharTraits
;
template
<>
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
private
:
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
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
>
...
...
@@ -579,17 +519,10 @@ 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
;
}
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
;
}
template
<
typename
T
>
static
int
format_float
(
wchar_t
*
buffer
,
std
::
size_t
size
,
...
...
@@ -598,49 +531,33 @@ public:
// Checks if a number is negative - used to avoid warnings.
template
<
bool
IsSigned
>
struct
SignChecker
{
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
>
{
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.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template
<
typename
T
>
inline
bool
is_negative
(
T
value
)
{
inline
bool
is_negative
(
T
value
)
{
return
SignChecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
is_negative
(
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
{
struct
IntTraits
{
// Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T.
typedef
typename
...
...
@@ -649,10 +566,7 @@ 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 <> \
...
...
@@ -670,8 +584,7 @@ void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// configuration.
template
<
typename
T
=
void
>
struct
BasicData
{
struct
BasicData
{
static
const
uint32_t
POWERS_OF_10_32
[];
static
const
uint64_t
POWERS_OF_10_64
[];
static
const
char
DIGITS
[];
...
...
@@ -690,8 +603,7 @@ typedef BasicData<> Data;
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
inline
unsigned
count_digits
(
uint64_t
n
)
{
inline
unsigned
count_digits
(
uint64_t
n
)
{
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
unsigned
t
=
(
64
-
FMT_BUILTIN_CLZLL
(
n
|
1
))
*
1233
>>
12
;
...
...
@@ -699,11 +611,9 @@ inline unsigned count_digits(uint64_t n)
}
#else
// Fallback version of count_digits used when __builtin_clz is not available.
inline
unsigned
count_digits
(
uint64_t
n
)
{
inline
unsigned
count_digits
(
uint64_t
n
)
{
unsigned
count
=
1
;
for
(;;)
{
for
(;;)
{
// Integer division is slow so do it for a group of four digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
...
@@ -719,8 +629,7 @@ inline unsigned count_digits(uint64_t n)
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline
unsigned
count_digits
(
uint32_t
n
)
{
inline
unsigned
count_digits
(
uint32_t
n
)
{
uint32_t
t
=
(
32
-
FMT_BUILTIN_CLZ
(
n
|
1
))
*
1233
>>
12
;
return
t
-
(
n
<
Data
::
POWERS_OF_10_32
[
t
])
+
1
;
}
...
...
@@ -728,11 +637,9 @@ inline unsigned count_digits(uint32_t n)
// Formats a decimal unsigned integer value writing into buffer.
template
<
typename
UInt
,
typename
Char
>
inline
void
format_decimal
(
Char
*
buffer
,
UInt
value
,
unsigned
num_digits
)
{
inline
void
format_decimal
(
Char
*
buffer
,
UInt
value
,
unsigned
num_digits
)
{
--
num_digits
;
while
(
value
>=
100
)
{
while
(
value
>=
100
)
{
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
...
@@ -742,8 +649,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
buffer
[
num_digits
-
1
]
=
Data
::
DIGITS
[
index
];
num_digits
-=
2
;
}
if
(
value
<
10
)
{
if
(
value
<
10
)
{
*
buffer
=
static_cast
<
char
>
(
'0'
+
value
);
return
;
}
...
...
@@ -755,57 +661,31 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
#ifdef _WIN32
// A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF8ToUTF16
{
private
:
class
UTF8ToUTF16
{
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
:
class
UTF16ToUTF8
{
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
...
...
@@ -822,42 +702,30 @@ void format_windows_error(fmt::Writer &out, int error_code,
fmt
::
StringRef
message
)
FMT_NOEXCEPT
;
#endif
// Computes max(
Arg
, 1) at compile time. It is used to avoid errors about
// Computes max(
N
, 1) at compile time. It is used to avoid errors about
// allocating an array of 0 size.
template
<
unsigned
Arg
>
struct
NonZero
{
enum
{
VALUE
=
Arg
};
template
<
unsigned
N
>
struct
NonZero
{
enum
{
VALUE
=
N
>
0
?
N
:
1
};
};
template
<>
struct
NonZero
<
0
>
{
enum
{
VALUE
=
1
};
};
// The value of a formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
struct
Value
{
// A formatting argument value.
struct
Value
{
template
<
typename
Char
>
struct
StringValue
{
struct
StringValue
{
const
Char
*
value
;
std
::
size_t
size
;
};
typedef
void
(
*
FormatFunc
)(
typedef
void
(
*
FormatFunc
)(
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
);
struct
CustomValue
{
struct
CustomValue
{
const
void
*
value
;
FormatFunc
format
;
};
union
{
union
{
int
int_value
;
unsigned
uint_value
;
LongLong
long_long_value
;
...
...
@@ -871,12 +739,8 @@ struct Value
StringValue
<
wchar_t
>
wstring
;
CustomValue
custom
;
};
};
struct
Arg
:
Value
{
enum
Type
{
enum
Type
{
NONE
,
// Integer types should go first,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
...
...
@@ -884,33 +748,78 @@ struct Arg : Value
DOUBLE
,
LONG_DOUBLE
,
LAST_NUMERIC_TYPE
=
LONG_DOUBLE
,
CSTRING
,
STRING
,
WSTRING
,
POINTER
,
CUSTOM
};
};
// A formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
struct
Arg
:
Value
{
Type
type
;
};
template
<
typename
T
>
template
<
typename
T
=
void
>
struct
None
{};
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
template
<
typename
T
,
typename
Char
>
struct
WCharHelper
{
struct
WCharHelper
{
typedef
None
<
T
>
Supported
;
typedef
T
Unsupported
;
};
template
<
typename
T
>
struct
WCharHelper
<
T
,
wchar_t
>
{
struct
WCharHelper
<
T
,
wchar_t
>
{
typedef
T
Supported
;
typedef
None
<
T
>
Unsupported
;
};
// Makes a Value object from any type.
template
<
typename
T
>
class
IsConvertibleToInt
{
private
:
typedef
char
yes
[
1
];
typedef
char
no
[
2
];
static
const
T
&
get
();
static
yes
&
check
(
fmt
::
ULongLong
);
static
no
&
check
(...);
public
:
enum
{
value
=
(
sizeof
(
check
(
get
()))
==
sizeof
(
yes
))
};
};
#define FMT_CONVERTIBLE_TO_INT(Type) \
template <> \
class IsConvertibleToInt<Type> { \
public: \
enum { value = 1 }; \
}
// Silence warnings about convering float to int.
FMT_CONVERTIBLE_TO_INT
(
float
);
FMT_CONVERTIBLE_TO_INT
(
double
);
FMT_CONVERTIBLE_TO_INT
(
long
double
);
template
<
bool
B
,
class
T
=
void
>
struct
EnableIf
{};
template
<
class
T
>
struct
EnableIf
<
true
,
T
>
{
typedef
T
type
;
};
template
<
bool
B
,
class
T
,
class
F
>
struct
Conditional
{
typedef
T
type
;
};
template
<
class
T
,
class
F
>
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
;
}
// Makes an Arg object from any type.
template
<
typename
Char
>
class
MakeValue
:
public
Value
{
private
:
class
MakeValue
:
public
Arg
{
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
...
...
@@ -931,14 +840,12 @@ private:
MakeValue
(
typename
WCharHelper
<
const
std
::
wstring
&
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
WStringRef
,
Char
>::
Unsupported
);
void
set_string
(
StringRef
str
)
{
void
set_string
(
StringRef
str
)
{
string
.
value
=
str
.
c_str
();
string
.
size
=
str
.
size
();
}
void
set_string
(
WStringRef
str
)
{
void
set_string
(
WStringRef
str
)
{
wstring
.
value
=
str
.
c_str
();
wstring
.
size
=
str
.
size
();
}
...
...
@@ -946,14 +853,13 @@ private:
// Formats an argument of a custom type, such as a user-defined class.
template
<
typename
T
>
static
void
format_custom_arg
(
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
)
{
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
)
{
format
(
*
static_cast
<
BasicFormatter
<
Char
>*>
(
formatter
),
*
static_cast
<
const
Char
**>
(
format_str_ptr
),
*
static_cast
<
const
T
*>
(
arg
));
}
public
:
public
:
MakeValue
()
{}
#define FMT_MAKE_VALUE(Type, field, TYPE) \
...
...
@@ -966,29 +872,25 @@ public:
FMT_MAKE_VALUE
(
int
,
int_value
,
INT
)
FMT_MAKE_VALUE
(
unsigned
,
uint_value
,
UINT
)
MakeValue
(
long
value
)
{
MakeValue
(
long
value
)
{
// To minimize the number of types we need to deal with, long is
// translated either to int or to long long depending on its size.
if
(
sizeof
(
long
)
==
sizeof
(
int
))
if
(
check
(
sizeof
(
long
)
==
sizeof
(
int
)
))
int_value
=
static_cast
<
int
>
(
value
);
else
long_long_value
=
value
;
}
static
uint64_t
type
(
long
)
{
static
uint64_t
type
(
long
)
{
return
sizeof
(
long
)
==
sizeof
(
int
)
?
Arg
::
INT
:
Arg
::
LONG_LONG
;
}
MakeValue
(
unsigned
long
value
)
{
if
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
))
MakeValue
(
unsigned
long
value
)
{
if
(
check
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)))
uint_value
=
static_cast
<
unsigned
>
(
value
);
else
ulong_long_value
=
value
;
}
static
uint64_t
type
(
unsigned
long
)
{
static
uint64_t
type
(
unsigned
long
)
{
return
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)
?
Arg
::
UINT
:
Arg
::
ULONG_LONG
;
}
...
...
@@ -1002,14 +904,10 @@ public:
FMT_MAKE_VALUE
(
unsigned
char
,
int_value
,
CHAR
)
FMT_MAKE_VALUE
(
char
,
int_value
,
CHAR
)
MakeValue
(
typename
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
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); } \
...
...
@@ -1037,15 +935,21 @@ public:
FMT_MAKE_VALUE
(
const
void
*
,
pointer
,
POINTER
)
template
<
typename
T
>
MakeValue
(
const
T
&
value
)
{
MakeValue
(
const
T
&
value
,
typename
EnableIf
<!
IsConvertibleToInt
<
T
>::
value
,
int
>::
type
=
0
)
{
custom
.
value
=
&
value
;
custom
.
format
=
&
format_custom_arg
<
T
>
;
}
template
<
typename
T
>
MakeValue
(
const
T
&
value
,
typename
EnableIf
<
IsConvertibleToInt
<
T
>::
value
,
int
>::
type
=
0
)
{
int_value
=
value
;
}
template
<
typename
T
>
static
uint64_t
type
(
const
T
&
)
{
return
Arg
::
CUSTOM
;
static
uint64_t
type
(
const
T
&
)
{
return
IsConvertibleToInt
<
T
>::
value
?
Arg
::
INT
:
Arg
::
CUSTOM
;
}
};
...
...
@@ -1072,75 +976,61 @@ public:
// ArgVisitor uses the curiously recurring template pattern:
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template
<
typename
Impl
,
typename
Result
>
class
ArgVisitor
{
public
:
Result
visit_unhandled_arg
()
{
class
ArgVisitor
{
public
:
void
report_unhandled_arg
()
{}
Result
visit_unhandled_arg
()
{
FMT_DISPATCH
(
report_unhandled_arg
());
return
Result
();
}
Result
visit_int
(
int
value
)
{
Result
visit_int
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
Result
visit_long_long
(
LongLong
value
)
{
Result
visit_long_long
(
LongLong
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
Result
visit_uint
(
unsigned
value
)
{
Result
visit_uint
(
unsigned
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
Result
visit_ulong_long
(
ULongLong
value
)
{
Result
visit_ulong_long
(
ULongLong
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
Result
visit_char
(
int
value
)
{
Result
visit_char
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
template
<
typename
T
>
Result
visit_any_int
(
T
)
{
Result
visit_any_int
(
T
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
Result
visit_double
(
double
value
)
{
Result
visit_double
(
double
value
)
{
return
FMT_DISPATCH
(
visit_any_double
(
value
));
}
Result
visit_long_double
(
long
double
value
)
{
Result
visit_long_double
(
long
double
value
)
{
return
FMT_DISPATCH
(
visit_any_double
(
value
));
}
template
<
typename
T
>
Result
visit_any_double
(
T
)
{
Result
visit_any_double
(
T
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
Result
visit_string
(
Arg
::
StringValue
<
char
>
)
{
Result
visit_string
(
Arg
::
StringValue
<
char
>
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
Result
visit_wstring
(
Arg
::
StringValue
<
wchar_t
>
)
{
Result
visit_wstring
(
Arg
::
StringValue
<
wchar_t
>
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
Result
visit_pointer
(
const
void
*
)
{
Result
visit_pointer
(
const
void
*
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
Result
visit_custom
(
Arg
::
CustomValue
)
{
Result
visit_custom
(
Arg
::
CustomValue
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
Result
visit
(
const
Arg
&
arg
)
{
switch
(
arg
.
type
)
{
Result
visit
(
const
Arg
&
arg
)
{
switch
(
arg
.
type
)
{
default
:
assert
(
false
);
return
Result
();
...
...
@@ -1158,9 +1048,8 @@ public:
return
FMT_DISPATCH
(
visit_long_double
(
arg
.
long_double_value
));
case
Arg
:
:
CHAR
:
return
FMT_DISPATCH
(
visit_char
(
arg
.
int_value
));
case
Arg
:
:
CSTRING
:
{
Value
::
StringValue
<
char
>
str
=
arg
.
string
;
case
Arg
:
:
CSTRING
:
{
Arg
::
StringValue
<
char
>
str
=
arg
.
string
;
str
.
size
=
0
;
return
FMT_DISPATCH
(
visit_string
(
str
));
}
...
...
@@ -1176,9 +1065,8 @@ public:
}
};
class
RuntimeError
:
public
std
::
runtime_error
{
protected
:
class
RuntimeError
:
public
std
::
runtime_error
{
protected
:
RuntimeError
()
:
std
::
runtime_error
(
""
)
{}
};
...
...
@@ -1186,66 +1074,88 @@ template <typename Char>
class
ArgFormatter
;
}
// namespace internal
/**
An argument list.
*/
class
ArgList
{
private
:
/** An argument list. */
class
ArgList
{
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_
;
union
{
// If the number of arguments is less than MAX_PACKED_ARGS, the argument
// values are stored in values_, otherwise they are stored in args_.
// This is done to reduce compiled code size as storing larger objects
// may require more code (at least on x86-64) even if the same amount of
// data is actually copied to stack. It saves ~10% on the bloat test.
const
internal
::
Value
*
values_
;
const
internal
::
Arg
*
args_
;
};
public
:
// Maximum number of arguments that can be passed in ArgList.
enum
{
MAX_ARGS
=
16
};
internal
::
Arg
::
Type
type
(
unsigned
index
)
const
{
unsigned
shift
=
index
*
4
;
uint64_t
mask
=
0xf
;
return
static_cast
<
internal
::
Arg
::
Type
>
(
(
types_
&
(
mask
<<
shift
))
>>
shift
);
}
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
)
:
types_
(
types
),
args_
(
args
)
{}
/**
Returns the argument at specified index.
*/
internal
::
Arg
operator
[](
unsigned
index
)
const
{
/** Returns the argument at specified index. */
internal
::
Arg
operator
[](
unsigned
index
)
const
{
using
internal
::
Arg
;
Arg
arg
;
if
(
index
>=
MAX_ARGS
)
{
bool
use_values
=
type
(
MAX_PACKED_ARGS
-
1
)
==
Arg
::
NONE
;
if
(
index
<
MAX_PACKED_ARGS
)
{
Arg
::
Type
arg_type
=
type
(
index
);
internal
::
Value
&
val
=
arg
;
if
(
arg_type
!=
Arg
::
NONE
)
val
=
use_values
?
values_
[
index
]
:
args_
[
index
];
arg
.
type
=
arg_type
;
return
arg
;
}
if
(
use_values
)
{
// The index is greater than the number of arguments that can be stored
// in values, so return a "none" argument.
arg
.
type
=
Arg
::
NONE
;
return
arg
;
}
unsigned
shift
=
index
*
4
;
uint64_t
mask
=
0xf
;
Arg
::
Type
type
=
static_cast
<
Arg
::
Type
>
((
types_
&
(
mask
<<
shift
))
>>
shift
);
arg
.
type
=
type
;
if
(
type
!=
Arg
::
NONE
)
{
internal
::
Value
&
value
=
arg
;
value
=
values_
[
index
];
for
(
unsigned
i
=
MAX_PACKED_ARGS
;
i
<=
index
;
++
i
)
{
if
(
args_
[
i
].
type
==
Arg
::
NONE
)
return
args_
[
i
];
}
return
arg
;
return
args_
[
index
]
;
}
};
struct
FormatSpec
;
namespace
internal
{
namespace
internal
{
template
<
std
::
size_t
NUM_ARGS
>
struct
SelectValueType
{
typedef
typename
Conditional
<
(
NUM_ARGS
<
ArgList
::
MAX_PACKED_ARGS
),
Value
,
Arg
>::
type
Type
;
};
class
FormatterBase
{
private
:
class
FormatterBase
{
private
:
ArgList
args_
;
int
next_arg_index_
;
// Returns the argument with specified index.
Arg
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
protected
:
void
set_args
(
const
ArgList
&
args
)
{
protected
:
void
set_args
(
const
ArgList
&
args
)
{
args_
=
args
;
next_arg_index_
=
0
;
}
...
...
@@ -1258,8 +1168,7 @@ protected:
Arg
get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
template
<
typename
Char
>
void
write
(
BasicWriter
<
Char
>
&
w
,
const
Char
*
start
,
const
Char
*
end
)
{
void
write
(
BasicWriter
<
Char
>
&
w
,
const
Char
*
start
,
const
Char
*
end
)
{
if
(
start
!=
end
)
w
<<
BasicStringRef
<
Char
>
(
start
,
end
-
start
);
}
...
...
@@ -1267,9 +1176,8 @@ protected:
// A printf formatter.
template
<
typename
Char
>
class
PrintfFormatter
:
private
FormatterBase
{
private
:
class
PrintfFormatter
:
private
FormatterBase
{
private
:
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
// Returns the argument with specified index or, if arg_index is equal
...
...
@@ -1280,7 +1188,7 @@ private:
// 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
,
BasicStringRef
<
Char
>
format_str
,
const
ArgList
&
args
);
};
...
...
@@ -1288,9 +1196,8 @@ public:
// A formatter.
template
<
typename
Char
>
class
BasicFormatter
:
private
internal
::
FormatterBase
{
private
:
class
BasicFormatter
:
private
internal
::
FormatterBase
{
private
:
BasicWriter
<
Char
>
&
writer_
;
const
Char
*
start_
;
...
...
@@ -1299,27 +1206,22 @@ private:
// Parses argument index and returns corresponding argument.
internal
::
Arg
parse_arg_index
(
const
Char
*&
s
);
public
:
public
:
explicit
BasicFormatter
(
BasicWriter
<
Char
>
&
w
)
:
writer_
(
w
)
{}
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
}
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
}
void
format
(
BasicStringRef
<
Char
>
format_str
,
const
ArgList
&
args
);
const
Char
*
format
(
const
Char
*&
format_str
,
const
internal
::
Arg
&
arg
);
};
enum
Alignment
{
enum
Alignment
{
ALIGN_DEFAULT
,
ALIGN_LEFT
,
ALIGN_RIGHT
,
ALIGN_CENTER
,
ALIGN_NUMERIC
};
// Flags.
enum
{
enum
{
SIGN_FLAG
=
1
,
PLUS_FLAG
=
2
,
MINUS_FLAG
=
4
,
HASH_FLAG
=
8
,
CHAR_FLAG
=
0x10
// Argument has char type - used in error reporting.
};
...
...
@@ -1329,37 +1231,17 @@ 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
' '
;
}
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
' '
;
}
};
// A width specifier.
struct
WidthSpec
{
struct
WidthSpec
{
unsigned
width_
;
// Fill is always wchar_t and cast to char if necessary to avoid having
// two specialization of WidthSpec and its subclasses.
...
...
@@ -1367,54 +1249,33 @@ 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.
struct
AlignSpec
:
WidthSpec
{
struct
AlignSpec
:
WidthSpec
{
Alignment
align_
;
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.
template
<
char
TYPE
>
struct
AlignTypeSpec
:
AlignSpec
{
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.
struct
FormatSpec
:
AlignSpec
{
struct
FormatSpec
:
AlignSpec
{
unsigned
flags_
;
int
precision_
;
char
type_
;
...
...
@@ -1423,90 +1284,73 @@ 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
:
class
IntFormatSpec
:
public
SpecT
{
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
>
class
StrFormatSpec
:
public
AlignSpec
{
private
:
class
StrFormatSpec
:
public
AlignSpec
{
private
:
const
T
*
str_
;
public
:
public
:
StrFormatSpec
(
const
T
*
str
,
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{}
const
T
*
str
()
const
{
return
str_
;
}
const
T
*
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
=
' '
);
...
...
@@ -1514,26 +1358,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 */
\
...
...
@@ -1545,20 +1389,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
)
...
...
@@ -1568,27 +1412,25 @@ 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
=
' '
)
{
const
Char
*
str
,
unsigned
width
,
Char
fill
=
' '
)
{
return
StrFormatSpec
<
Char
>
(
str
,
width
,
fill
);
}
inline
StrFormatSpec
<
wchar_t
>
pad
(
const
wchar_t
*
str
,
unsigned
width
,
char
fill
=
' '
)
{
const
wchar_t
*
str
,
unsigned
width
,
char
fill
=
' '
)
{
return
StrFormatSpec
<
wchar_t
>
(
str
,
width
,
fill
);
}
...
...
@@ -1611,29 +1453,20 @@ inline StrFormatSpec<wchar_t> pad(
# define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace
internal
{
inline
uint64_t
make_type
()
{
return
0
;
}
namespace
internal
{
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
);
}
#if FMT_USE_VARIADIC_TEMPLATES
template
<
typename
Arg
,
typename
...
Args
>
inline
uint64_t
make_type
(
const
Arg
&
first
,
const
Args
&
...
tail
)
{
inline
uint64_t
make_type
(
const
Arg
&
first
,
const
Args
&
...
tail
)
{
return
make_type
(
first
)
|
(
make_type
(
tail
...)
<<
4
);
}
#else
struct
ArgType
{
struct
ArgType
{
uint64_t
type
;
ArgType
()
:
type
(
0
)
{}
...
...
@@ -1644,8 +1477,7 @@ struct ArgType
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
inline
uint64_t
make_type
(
FMT_GEN15
(
FMT_ARG_TYPE_DEFAULT
))
{
inline
uint64_t
make_type
(
FMT_GEN15
(
FMT_ARG_TYPE_DEFAULT
))
{
return
t0
.
type
|
(
t1
.
type
<<
4
)
|
(
t2
.
type
<<
8
)
|
(
t3
.
type
<<
12
)
|
(
t4
.
type
<<
16
)
|
(
t5
.
type
<<
20
)
|
(
t6
.
type
<<
24
)
|
(
t7
.
type
<<
28
)
|
(
t8
.
type
<<
32
)
|
(
t9
.
type
<<
36
)
|
(
t10
.
type
<<
40
)
|
(
t11
.
type
<<
44
)
|
...
...
@@ -1664,24 +1496,25 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
// Defines a variadic function returning void.
# define FMT_VARIADIC_VOID(func, arg_type) \
template <typename... Args> \
void func(arg_type arg1, const Args & ... args) { \
const fmt::internal::Value values[ \
fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \
fmt::internal::MakeValue<Char>(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(arg
1, ArgList(fmt::internal::make_type(args...), values
)); \
func(arg
0, ArgList(internal::make_type(args...), array
)); \
}
// 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) { \
using fmt::internal::MakeValue
; \
const fmt::internal::Value values[
\
fmt::
internal::NonZero<sizeof...(Args)>::VALUE] = { \
MakeValue<Char>(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(
fmt::internal::make_type(args...), values
)); \
func(arg0, arg1, ArgList(
internal::make_type(args...), array
)); \
}
#else
...
...
@@ -1694,9 +1527,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 vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::Value val
ue
s[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), val
ue
s)); \
}
// Emulates a variadic function returning void on a pre-C++11 compiler.
...
...
@@ -1711,9 +1544,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 vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::Value val
ue
s[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg0, arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), val
ue
s)); \
}
// Emulates a variadic constructor on a pre-C++11 compiler.
...
...
@@ -1753,22 +1586,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
:
class
SystemError
:
public
internal
::
RuntimeError
{
private
:
void
init
(
int
err_code
,
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
...
...
@@ -1794,42 +1626,37 @@ public:
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst
*/
SystemError
(
int
error_code
,
StringRef
message
)
{
SystemError
(
int
error_code
,
StringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
}
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
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
:
class
BasicWriter
{
private
:
// Output buffer.
internal
::
Buffer
<
Char
>
&
buffer_
;
Buffer
<
Char
>
&
buffer_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
BasicWriter
);
...
...
@@ -1837,15 +1664,9 @@ private:
#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
...
...
@@ -1855,8 +1676,7 @@ private:
// Grows the buffer by n characters and returns a pointer to the newly
// allocated area.
CharPtr
grow_buffer
(
std
::
size_t
n
)
{
CharPtr
grow_buffer
(
std
::
size_t
n
)
{
std
::
size_t
size
=
buffer_
.
size
();
buffer_
.
resize
(
size
+
n
);
return
internal
::
make_ptr
(
&
buffer_
[
size
],
n
);
...
...
@@ -1864,8 +1684,7 @@ private:
// Prepare a buffer for integer formatting.
CharPtr
prepare_int_buffer
(
unsigned
num_digits
,
const
EmptySpec
&
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
const
EmptySpec
&
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
unsigned
size
=
prefix_size
+
num_digits
;
CharPtr
p
=
grow_buffer
(
size
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
...
...
@@ -1903,8 +1722,7 @@ private:
// Appends floating-point length specifier to the format string.
// The second argument is only used for overload resolution.
void
append_float_length
(
Char
*&
format_ptr
,
long
double
)
{
void
append_float_length
(
Char
*&
format_ptr
,
long
double
)
{
*
format_ptr
++
=
'L'
;
}
...
...
@@ -1914,13 +1732,13 @@ private:
friend
class
internal
::
ArgFormatter
<
Char
>
;
friend
class
internal
::
PrintfFormatter
<
Char
>
;
protected
:
protected
:
/**
Constructs a ``BasicWriter`` object.
*/
explicit
BasicWriter
(
internal
::
Buffer
<
Char
>
&
b
)
:
buffer_
(
b
)
{}
explicit
BasicWriter
(
Buffer
<
Char
>
&
b
)
:
buffer_
(
b
)
{}
public
:
public
:
/**
Destroys a ``BasicWriter`` object.
*/
...
...
@@ -1929,26 +1747,19 @@ public:
/**
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
character appended.
*/
const
Char
*
c_str
()
const
{
const
Char
*
c_str
()
const
{
std
::
size_t
size
=
buffer_
.
size
();
buffer_
.
reserve
(
size
+
1
);
buffer_
[
size
]
=
'\0'
;
...
...
@@ -1958,8 +1769,7 @@ public:
/**
Returns the content of the output buffer as an `std::string`.
*/
std
::
basic_string
<
Char
>
str
()
const
{
std
::
basic_string
<
Char
>
str
()
const
{
return
std
::
basic_string
<
Char
>
(
&
buffer_
[
0
],
buffer_
.
size
());
}
...
...
@@ -1988,43 +1798,35 @@ public:
See also :ref:`syntax`.
\endrst
*/
void
write
(
BasicStringRef
<
Char
>
format
,
ArgList
args
)
{
void
write
(
BasicStringRef
<
Char
>
format
,
ArgList
args
)
{
BasicFormatter
<
Char
>
(
*
this
).
format
(
format
,
args
);
}
FMT_VARIADIC_VOID
(
write
,
BasicStringRef
<
Char
>
)
BasicWriter
&
operator
<<
(
int
value
)
{
BasicWriter
&
operator
<<
(
int
value
)
{
return
*
this
<<
IntFormatSpec
<
int
>
(
value
);
}
BasicWriter
&
operator
<<
(
unsigned
value
)
{
BasicWriter
&
operator
<<
(
unsigned
value
)
{
return
*
this
<<
IntFormatSpec
<
unsigned
>
(
value
);
}
BasicWriter
&
operator
<<
(
long
value
)
{
BasicWriter
&
operator
<<
(
long
value
)
{
return
*
this
<<
IntFormatSpec
<
long
>
(
value
);
}
BasicWriter
&
operator
<<
(
unsigned
long
value
)
{
BasicWriter
&
operator
<<
(
unsigned
long
value
)
{
return
*
this
<<
IntFormatSpec
<
unsigned
long
>
(
value
);
}
BasicWriter
&
operator
<<
(
LongLong
value
)
{
BasicWriter
&
operator
<<
(
LongLong
value
)
{
return
*
this
<<
IntFormatSpec
<
LongLong
>
(
value
);
}
/**
Formats *value* and writes it to the stream.
*/
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
return
*
this
<<
IntFormatSpec
<
ULongLong
>
(
value
);
}
BasicWriter
&
operator
<<
(
double
value
)
{
BasicWriter
&
operator
<<
(
double
value
)
{
write_double
(
value
,
FormatSpec
());
return
*
this
;
}
...
...
@@ -2033,8 +1835,7 @@ public:
Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream.
*/
BasicWriter
&
operator
<<
(
long
double
value
)
{
BasicWriter
&
operator
<<
(
long
double
value
)
{
write_double
(
value
,
FormatSpec
());
return
*
this
;
}
...
...
@@ -2042,15 +1843,13 @@ public:
/**
Writes a character to the stream.
*/
BasicWriter
&
operator
<<
(
char
value
)
{
BasicWriter
&
operator
<<
(
char
value
)
{
buffer_
.
push_back
(
value
);
return
*
this
;
}
BasicWriter
&
operator
<<
(
typename
internal
::
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
typename
internal
::
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
buffer_
.
push_back
(
value
);
return
*
this
;
}
...
...
@@ -2058,24 +1857,21 @@ public:
/**
Writes *value* to the stream.
*/
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
const
Char
*
str
=
value
.
c_str
();
buffer_
.
append
(
str
,
str
+
value
.
size
());
return
*
this
;
}
template
<
typename
T
,
typename
Spec
,
typename
FillChar
>
BasicWriter
&
operator
<<
(
IntFormatSpec
<
T
,
Spec
,
FillChar
>
spec
)
{
BasicWriter
&
operator
<<
(
IntFormatSpec
<
T
,
Spec
,
FillChar
>
spec
)
{
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
write_int
(
spec
.
value
(),
spec
);
return
*
this
;
}
template
<
typename
StrChar
>
BasicWriter
&
operator
<<
(
const
StrFormatSpec
<
StrChar
>
&
spec
)
{
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
);
...
...
@@ -2088,29 +1884,20 @@ public:
template
<
typename
Char
>
template
<
typename
StrChar
>
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
write_str
(
const
StrChar
*
s
,
std
::
size_t
size
,
const
AlignSpec
&
spec
)
{
const
StrChar
*
s
,
std
::
size_t
size
,
const
AlignSpec
&
spec
)
{
CharPtr
out
=
CharPtr
();
if
(
spec
.
width
()
>
size
)
{
if
(
spec
.
width
()
>
size
)
{
out
=
grow_buffer
(
spec
.
width
());
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
if
(
spec
.
align
()
==
ALIGN_RIGHT
)
{
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
);
...
...
@@ -2119,10 +1906,9 @@ 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
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
);
...
...
@@ -2136,15 +1922,13 @@ BasicWriter<Char>::fill_padding(
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
)
{
const
char
*
prefix
,
unsigned
prefix_size
)
{
unsigned
width
=
spec
.
width
();
Alignment
align
=
spec
.
align
();
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
if
(
spec
.
precision
()
>
static_cast
<
int
>
(
num_digits
))
{
if
(
spec
.
precision
()
>
static_cast
<
int
>
(
num_digits
))
{
// Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified.
if
(
prefix_size
>
0
&&
prefix
[
prefix_size
-
1
]
==
'0'
)
...
...
@@ -2155,53 +1939,41 @@ BasicWriter<Char>::prepare_int_buffer(
return
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
buffer_
.
reserve
(
width
);
unsigned
fill_size
=
width
-
number_size
;
if
(
align
!=
ALIGN_LEFT
)
{
if
(
align
!=
ALIGN_LEFT
)
{
CharPtr
p
=
grow_buffer
(
fill_size
);
std
::
fill
(
p
,
p
+
fill_size
,
fill
);
}
CharPtr
result
=
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
if
(
align
==
ALIGN_LEFT
)
{
if
(
align
==
ALIGN_LEFT
)
{
CharPtr
p
=
grow_buffer
(
fill_size
);
std
::
fill
(
p
,
p
+
fill_size
,
fill
);
}
return
result
;
}
unsigned
size
=
prefix_size
+
num_digits
;
if
(
width
<=
size
)
{
if
(
width
<=
size
)
{
CharPtr
p
=
grow_buffer
(
size
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
return
p
+
size
-
1
;
}
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
end
=
p
+
width
;
if
(
align
==
ALIGN_LEFT
)
{
if
(
align
==
ALIGN_LEFT
)
{
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
{
if
(
align
==
ALIGN_NUMERIC
)
{
if
(
prefix_size
!=
0
)
{
}
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
);
...
...
@@ -2212,103 +1984,77 @@ BasicWriter<Char>::prepare_int_buffer(
template
<
typename
Char
>
template
<
typename
T
,
typename
Spec
>
void
BasicWriter
<
Char
>::
write_int
(
T
value
,
Spec
spec
)
{
void
BasicWriter
<
Char
>::
write_int
(
T
value
,
Spec
spec
)
{
unsigned
prefix_size
=
0
;
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
UnsignedType
abs_value
=
value
;
char
prefix
[
4
]
=
""
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
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'
:
{
switch
(
spec
.
type
())
{
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
))
{
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
spec
.
type
();
}
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
}
while
((
n
>>=
4
)
!=
0
);
}
while
((
n
>>=
4
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
const
char
*
digits
=
spec
.
type
()
==
'x'
?
"0123456789abcdef"
:
"0123456789ABCDEF"
;
do
{
do
{
*
p
--
=
digits
[
n
&
0xf
];
}
while
((
n
>>=
4
)
!=
0
);
}
while
((
n
>>=
4
)
!=
0
);
break
;
}
case
'b'
:
case
'B'
:
{
case
'b'
:
case
'B'
:
{
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
spec
.
type
();
}
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
}
while
((
n
>>=
1
)
!=
0
);
}
while
((
n
>>=
1
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
do
{
do
{
*
p
--
=
'0'
+
(
n
&
1
);
}
while
((
n
>>=
1
)
!=
0
);
}
while
((
n
>>=
1
)
!=
0
);
break
;
}
case
'o'
:
{
case
'o'
:
{
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
prefix
[
prefix_size
++
]
=
'0'
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
}
while
((
n
>>=
3
)
!=
0
);
}
while
((
n
>>=
3
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
do
{
do
{
*
p
--
=
'0'
+
(
n
&
7
);
}
while
((
n
>>=
3
)
!=
0
);
}
while
((
n
>>=
3
)
!=
0
);
break
;
}
default
:
...
...
@@ -2321,20 +2067,15 @@ void BasicWriter<Char>::write_int(T value, Spec spec)
template
<
typename
Char
>
template
<
typename
T
>
void
BasicWriter
<
Char
>::
write_double
(
T
value
,
const
FormatSpec
&
spec
)
{
T
value
,
const
FormatSpec
&
spec
)
{
// Check type.
char
type
=
spec
.
type
();
bool
upper
=
false
;
switch
(
type
)
{
switch
(
type
)
{
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
...
...
@@ -2342,9 +2083,7 @@ 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
:
...
...
@@ -2355,24 +2094,19 @@ void BasicWriter<Char>::write_double(
char
sign
=
0
;
// Use getsign instead of value < 0 because the latter is always
// false for NaN.
if
(
internal
::
getsign
(
static_cast
<
double
>
(
value
)))
{
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
)
?
'+'
:
' '
;
}
if
(
value
!=
value
)
{
if
(
value
!=
value
)
{
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
std
::
size_t
nan_size
=
4
;
const
char
*
nan
=
upper
?
" NAN"
:
" nan"
;
if
(
!
sign
)
{
if
(
!
sign
)
{
--
nan_size
;
++
nan
;
}
...
...
@@ -2382,14 +2116,12 @@ void BasicWriter<Char>::write_double(
return
;
}
if
(
internal
::
isinfinity
(
value
))
{
if
(
internal
::
isinfinity
(
value
))
{
// Format infinity ourselves because sprintf's output is not consistent
// across platforms.
std
::
size_t
inf_size
=
4
;
const
char
*
inf
=
upper
?
" INF"
:
" inf"
;
if
(
!
sign
)
{
if
(
!
sign
)
{
--
inf_size
;
++
inf
;
}
...
...
@@ -2401,8 +2133,7 @@ void BasicWriter<Char>::write_double(
std
::
size_t
offset
=
buffer_
.
size
();
unsigned
width
=
spec
.
width
();
if
(
sign
)
{
if
(
sign
)
{
buffer_
.
reserve
(
buffer_
.
size
()
+
(
std
::
max
)(
width
,
1u
));
if
(
width
>
0
)
--
width
;
...
...
@@ -2410,26 +2141,22 @@ 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
++
=
'%'
;
unsigned
width_for_sprintf
=
width
;
if
(
spec
.
flag
(
HASH_FLAG
))
*
format_ptr
++
=
'#'
;
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
width_for_sprintf
=
0
;
}
else
{
}
else
{
if
(
spec
.
align
()
==
ALIGN_LEFT
)
*
format_ptr
++
=
'-'
;
if
(
width
!=
0
)
*
format_ptr
++
=
'*'
;
}
if
(
spec
.
precision
()
>=
0
)
{
if
(
spec
.
precision
()
>=
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
}
...
...
@@ -2440,15 +2167,13 @@ void BasicWriter<Char>::write_double(
// Format using snprintf.
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
for
(;;)
{
for
(;;)
{
std
::
size_t
buffer_size
=
buffer_
.
capacity
()
-
offset
;
#if _MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity will increase by more than 1.
if
(
buffer_size
==
0
)
{
if
(
buffer_size
==
0
)
{
buffer_
.
reserve
(
offset
+
1
);
buffer_size
=
buffer_
.
capacity
()
-
offset
;
}
...
...
@@ -2456,33 +2181,26 @@ void BasicWriter<Char>::write_double(
Char
*
start
=
&
buffer_
[
offset
];
int
n
=
internal
::
CharTraits
<
Char
>::
format_float
(
start
,
buffer_size
,
format
,
width_for_sprintf
,
spec
.
precision
(),
value
);
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
capacity
())
{
if
(
sign
)
{
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
capacity
())
{
if
(
sign
)
{
if
((
spec
.
align
()
!=
ALIGN_RIGHT
&&
spec
.
align
()
!=
ALIGN_DEFAULT
)
||
*
start
!=
' '
)
{
*
start
!=
' '
)
{
*
(
start
-
1
)
=
sign
;
sign
=
0
;
}
else
{
}
else
{
*
(
start
-
1
)
=
fill
;
}
++
n
;
}
if
(
spec
.
align
()
==
ALIGN_CENTER
&&
spec
.
width
()
>
static_cast
<
unsigned
>
(
n
))
{
spec
.
width
()
>
static_cast
<
unsigned
>
(
n
))
{
width
=
spec
.
width
();
CharPtr
p
=
grow_buffer
(
width
);
std
::
copy
(
p
,
p
+
n
,
p
+
(
width
-
n
)
/
2
);
fill_padding
(
p
,
spec
.
width
(),
n
,
fill
);
return
;
}
if
(
spec
.
fill
()
!=
' '
||
sign
)
{
if
(
spec
.
fill
()
!=
' '
||
sign
)
{
while
(
*
start
==
' '
)
*
start
++
=
fill
;
if
(
sign
)
...
...
@@ -2498,64 +2216,65 @@ void BasicWriter<Char>::write_double(
}
/**
\rst
This 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 | Basic
Writer<char, std::allocator<char>> |
+---------------+
-----------------------------------------------+
| WMemoryWriter | Basic
Writer<wchar_t, std::allocator<wchar_t>> |
+---------------+
-----------------------------------------------+
+---------------+------
-----------------------------------------------+
| Type | Definition
|
+===============+======
===============================================+
| MemoryWriter | BasicMemory
Writer<char, std::allocator<char>> |
+---------------+------
-----------------------------------------------+
| WMemoryWriter | BasicMemory
Writer<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
:
class
BasicMemoryWriter
:
public
BasicWriter
<
Char
>
{
private
:
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
,
Allocator
>
buffer_
;
public
:
public
:
explicit
BasicMemoryWriter
(
const
Allocator
&
alloc
=
Allocator
())
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
alloc
)
{}
#if FMT_USE_RVALUE_REFERENCES
/**
\rst
Constructs a :class:`fmt::BasicMemoryWriter` object moving the content
of the other object to it.
\endrst
*/
BasicMemoryWriter
(
BasicMemoryWriter
&&
other
)
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
std
::
move
(
other
.
buffer_
))
{
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
std
::
move
(
other
.
buffer_
))
{
}
/**
\rst
Moves the content of the other ``BasicMemoryWriter`` object to this one.
\endrst
*/
BasicMemoryWriter
&
operator
=
(
BasicMemoryWriter
&&
other
)
{
BasicMemoryWriter
&
operator
=
(
BasicMemoryWriter
&&
other
)
{
buffer_
=
std
::
move
(
other
.
buffer_
);
return
*
this
;
}
...
...
@@ -2565,16 +2284,63 @@ public:
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
*/
template
<
typename
Char
>
class
BasicArrayWriter
:
public
BasicWriter
<
Char
>
{
private
:
internal
::
FixedBuffer
<
Char
>
buffer_
;
public
:
/**
\rst
Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
given size.
\endrst
*/
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
])
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
array
,
SIZE
)
{}
};
typedef
BasicArrayWriter
<
char
>
ArrayWriter
;
typedef
BasicArrayWriter
<
wchar_t
>
WArrayWriter
;
// Formats a value.
template
<
typename
Char
,
typename
T
>
void
format
(
BasicFormatter
<
Char
>
&
f
,
const
Char
*&
format_str
,
const
T
&
value
)
{
void
format
(
BasicFormatter
<
Char
>
&
f
,
const
Char
*&
format_str
,
const
T
&
value
)
{
std
::
basic_ostringstream
<
Char
>
os
;
os
<<
value
;
internal
::
Arg
arg
;
internal
::
Value
&
arg_value
=
arg
;
std
::
basic_string
<
Char
>
str
=
os
.
str
();
arg_value
=
internal
::
MakeValue
<
Char
>
(
str
);
internal
::
Arg
arg
=
internal
::
MakeValue
<
Char
>
(
str
);
arg
.
type
=
static_cast
<
internal
::
Arg
::
Type
>
(
internal
::
MakeValue
<
Char
>::
type
(
str
));
format_str
=
f
.
format
(
format_str
,
arg
);
...
...
@@ -2587,12 +2353,11 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32
/** A Windows error. */
class
WindowsError
:
public
SystemError
{
private
:
class
WindowsError
:
public
SystemError
{
private
:
void
init
(
int
error_code
,
StringRef
format_str
,
ArgList
args
);
public
:
public
:
/**
\rst
Constructs a :class:`fmt::WindowsError` object with the description
...
...
@@ -2621,8 +2386,7 @@ public:
}
\endrst
*/
WindowsError
(
int
error_code
,
StringRef
message
)
{
WindowsError
(
int
error_code
,
StringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
}
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
StringRef
)
...
...
@@ -2637,134 +2401,126 @@ 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;
*/
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
);
/**
\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
(
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
(
WStringRef
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
*/
print(stderr, "Don't {}!", "panic");
\endrst
*/
void
print
(
std
::
FILE
*
f
,
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
*/
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
void
print
(
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
*/
print(cerr, "Don't {}!", "panic");
\endrst
*/
void
print
(
std
::
ostream
&
os
,
StringRef
format_str
,
ArgList
args
);
template
<
typename
Char
>
void
printf
(
BasicWriter
<
Char
>
&
w
,
BasicStringRef
<
Char
>
format
,
ArgList
args
)
{
void
printf
(
BasicWriter
<
Char
>
&
w
,
BasicStringRef
<
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
(
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
*/
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
int
fprintf
(
std
::
FILE
*
f
,
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
(
StringRef
format
,
ArgList
args
)
{
return
fprintf
(
stdout
,
format
,
args
);
}
/**
Fast integer formatter.
*/
class
FormatInt
{
private
:
Fast integer formatter.
*/
class
FormatInt
{
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_
;
// Formats value in reverse and returns the number of digits.
char
*
format_decimal
(
ULongLong
value
)
{
char
*
format_decimal
(
ULongLong
value
)
{
char
*
buffer_end
=
buffer_
+
BUFFER_SIZE
-
1
;
while
(
value
>=
100
)
{
while
(
value
>=
100
)
{
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
...
@@ -2773,8 +2529,7 @@ private:
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
+
1
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
];
}
if
(
value
<
10
)
{
if
(
value
<
10
)
{
*--
buffer_end
=
static_cast
<
char
>
(
'0'
+
value
);
return
buffer_end
;
}
...
...
@@ -2784,8 +2539,7 @@ private:
return
buffer_end
;
}
void
FormatSigned
(
LongLong
value
)
{
void
FormatSigned
(
LongLong
value
)
{
ULongLong
abs_value
=
static_cast
<
ULongLong
>
(
value
);
bool
negative
=
value
<
0
;
if
(
negative
)
...
...
@@ -2795,19 +2549,10 @@ private:
*--
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
))
{}
...
...
@@ -2815,26 +2560,19 @@ public:
/**
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
character appended.
*/
const
char
*
c_str
()
const
{
const
char
*
c_str
()
const
{
buffer_
[
BUFFER_SIZE
-
1
]
=
'\0'
;
return
str_
;
}
...
...
@@ -2842,28 +2580,21 @@ public:
/**
Returns the content of the output buffer as an `std::string`.
*/
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
// a pointer to the end of the formatted string. This function doesn't
// write a terminating null character.
template
<
typename
T
>
inline
void
format_decimal
(
char
*&
buffer
,
T
value
)
{
inline
void
format_decimal
(
char
*&
buffer
,
T
value
)
{
typename
internal
::
IntTraits
<
T
>::
MainType
abs_value
=
value
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
*
buffer
++
=
'-'
;
abs_value
=
0
-
abs_value
;
}
if
(
abs_value
<
100
)
{
if
(
abs_value
<
10
)
{
if
(
abs_value
<
100
)
{
if
(
abs_value
<
10
)
{
*
buffer
++
=
static_cast
<
char
>
(
'0'
+
abs_value
);
return
;
}
...
...
@@ -2906,16 +2637,52 @@ 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) { \
using fmt::internal::Value; \
const Value values[fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \
fmt::internal::MakeValue<Char>(args)... \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
Value array[internal::ArgArraySize<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
fmt::internal::make_type(args...), values)); \
if (internal::check((sizeof...(Args) > fmt::ArgList::MAX_PACKED_ARGS))) \
set_types(array, args...); \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(internal::make_type(args...), array)); \
}
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
...
...
@@ -2924,9 +2691,9 @@ inline void format_decimal(char *&buffer, T value)
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 vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \
const fmt::internal::Value val
ue
s[] = {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)), vals)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), val
ue
s)); \
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
...
...
@@ -2951,40 +2718,39 @@ inline void format_decimal(char *&buffer, T value)
#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__)
namespace
fmt
{
namespace
fmt
{
FMT_VARIADIC
(
std
::
string
,
format
,
StringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
WStringRef
)
FMT_VARIADIC
(
void
,
print
,
StringRef
)
...
...
@@ -3004,6 +2770,7 @@ FMT_VARIADIC(int, fprintf, std::FILE *, StringRef)
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#ifdef FMT_HEADER_ONLY
# include "format.cc"
#endif
...
...
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