Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
spdlog
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
spdlog
Commits
1150247e
Commit
1150247e
authored
Mar 21, 2015
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
astyle
parent
a24ff547
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
562 additions
and
285 deletions
+562
-285
example/example.cpp
example/example.cpp
+2
-1
include/spdlog/details/async_log_helper.h
include/spdlog/details/async_log_helper.h
+5
-5
include/spdlog/details/format.h
include/spdlog/details/format.h
+555
-279
No files found.
example/example.cpp
View file @
1150247e
...
@@ -112,7 +112,8 @@ int main(int, char*[])
...
@@ -112,7 +112,8 @@ int main(int, char*[])
// Example of user defined class with operator<<
// Example of user defined class with operator<<
class
some_class
{};
class
some_class
{};
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
some_class
&
)
{
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
some_class
&
)
{
return
os
<<
"some_class"
;
return
os
<<
"some_class"
;
}
}
...
...
include/spdlog/details/async_log_helper.h
View file @
1150247e
...
@@ -64,7 +64,7 @@ class async_log_helper
...
@@ -64,7 +64,7 @@ class async_log_helper
async_msg
()
=
default
;
async_msg
()
=
default
;
~
async_msg
()
=
default
;
~
async_msg
()
=
default
;
async_msg
(
async_msg
&&
other
)
SPDLOG_NOEXCEPT
:
async_msg
(
async_msg
&&
other
)
SPDLOG_NOEXCEPT
:
logger_name
(
std
::
move
(
other
.
logger_name
)),
logger_name
(
std
::
move
(
other
.
logger_name
)),
level
(
std
::
move
(
other
.
level
)),
level
(
std
::
move
(
other
.
level
)),
time
(
std
::
move
(
other
.
time
)),
time
(
std
::
move
(
other
.
time
)),
...
...
include/spdlog/details/format.h
View file @
1150247e
...
@@ -49,10 +49,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
...
@@ -49,10 +49,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef _MSC_VER
#ifdef _MSC_VER
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
namespace
fmt
{
namespace
fmt
namespace
internal
{
{
namespace
internal
{
# pragma intrinsic(_BitScanReverse)
# pragma intrinsic(_BitScanReverse)
inline
uint32_t
clz
(
uint32_t
x
)
{
inline
uint32_t
clz
(
uint32_t
x
)
{
unsigned
long
r
=
0
;
unsigned
long
r
=
0
;
_BitScanReverse
(
&
r
,
x
);
_BitScanReverse
(
&
r
,
x
);
return
31
-
r
;
return
31
-
r
;
...
@@ -63,7 +66,8 @@ inline uint32_t clz(uint32_t x) {
...
@@ -63,7 +66,8 @@ inline uint32_t clz(uint32_t x) {
# pragma intrinsic(_BitScanReverse64)
# pragma intrinsic(_BitScanReverse64)
# endif
# endif
inline
uint32_t
clzll
(
uint64_t
x
)
{
inline
uint32_t
clzll
(
uint64_t
x
)
{
unsigned
long
r
=
0
;
unsigned
long
r
=
0
;
# ifdef _WIN64
# ifdef _WIN64
_BitScanReverse64
(
&
r
,
x
);
_BitScanReverse64
(
&
r
,
x
);
...
@@ -174,7 +178,8 @@ inline uint32_t clzll(uint64_t x) {
...
@@ -174,7 +178,8 @@ inline uint32_t clzll(uint64_t x) {
TypeName& operator=(const TypeName&)
TypeName& operator=(const TypeName&)
#endif
#endif
namespace
fmt
{
namespace
fmt
{
// Fix the warning about long long on older versions of GCC
// Fix the warning about long long on older versions of GCC
// that don't support the diagnostic pragma.
// that don't support the diagnostic pragma.
...
@@ -223,7 +228,8 @@ format(std::string("{}"), 42);
...
@@ -223,7 +228,8 @@ format(std::string("{}"), 42);
\endrst
\endrst
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicStringRef
{
class
BasicStringRef
{
private:
private:
const
Char
*
data_
;
const
Char
*
data_
;
std
::
size_t
size_
;
std
::
size_t
size_
;
...
@@ -250,28 +256,33 @@ public:
...
@@ -250,28 +256,33 @@ public:
/**
/**
Converts a string reference to an `std::string` object.
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
());
return
std
::
basic_string
<
Char
>
(
data_
,
size
());
}
}
/**
/**
Returns the pointer to a C string.
Returns the pointer to a C string.
*/
*/
const
Char
*
c_str
()
const
{
const
Char
*
c_str
()
const
{
return
data_
;
return
data_
;
}
}
/**
/**
Returns the string size.
Returns the string size.
*/
*/
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
size_
;
return
size_
;
}
}
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
==
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
data_
==
rhs
.
data_
;
return
lhs
.
data_
==
rhs
.
data_
;
}
}
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
friend
bool
operator
!=
(
BasicStringRef
lhs
,
BasicStringRef
rhs
)
{
return
lhs
.
data_
!=
rhs
.
data_
;
return
lhs
.
data_
!=
rhs
.
data_
;
}
}
};
};
...
@@ -282,13 +293,15 @@ typedef BasicStringRef<wchar_t> WStringRef;
...
@@ -282,13 +293,15 @@ 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
{
class
FormatError
:
public
std
::
runtime_error
{
public:
public:
explicit
FormatError
(
StringRef
message
)
explicit
FormatError
(
StringRef
message
)
:
std
::
runtime_error
(
message
.
c_str
())
{}
:
std
::
runtime_error
(
message
.
c_str
())
{}
};
};
namespace
internal
{
namespace
internal
{
// The number of characters to store in the MemoryBuffer object itself
// The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation.
// to avoid dynamic memory allocation.
...
@@ -297,19 +310,22 @@ enum { INLINE_BUFFER_SIZE = 500 };
...
@@ -297,19 +310,22 @@ enum { INLINE_BUFFER_SIZE = 500 };
#if _SECURE_SCL
#if _SECURE_SCL
// Use checked iterator to avoid warnings on MSVC.
// Use checked iterator to avoid warnings on MSVC.
template
<
typename
T
>
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
);
return
stdext
::
checked_array_iterator
<
T
*>
(
ptr
,
size
);
}
}
#else
#else
template
<
typename
T
>
template
<
typename
T
>
inline
T
*
make_ptr
(
T
*
ptr
,
std
::
size_t
)
{
inline
T
*
make_ptr
(
T
*
ptr
,
std
::
size_t
)
{
return
ptr
;
return
ptr
;
}
}
#endif
#endif
// A buffer for POD types. It supports a subset of std::vector's operations.
// A buffer for POD types. It supports a subset of std::vector's operations.
template
<
typename
T
>
template
<
typename
T
>
class
Buffer
{
class
Buffer
{
private:
private:
FMT_DISALLOW_COPY_AND_ASSIGN
(
Buffer
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
Buffer
);
...
@@ -327,31 +343,36 @@ public:
...
@@ -327,31 +343,36 @@ public:
virtual
~
Buffer
()
{}
virtual
~
Buffer
()
{}
// Returns the size of this buffer.
// Returns the size of this buffer.
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
size_
;
return
size_
;
}
}
// Returns the capacity of this buffer.
// Returns the capacity of this buffer.
std
::
size_t
capacity
()
const
{
std
::
size_t
capacity
()
const
{
return
capacity_
;
return
capacity_
;
}
}
// Resizes the buffer. If T is a POD type new elements are not initialized.
// Resizes the buffer. If T is a POD type new elements are not initialized.
void
resize
(
std
::
size_t
new_size
)
{
void
resize
(
std
::
size_t
new_size
)
{
if
(
new_size
>
capacity_
)
if
(
new_size
>
capacity_
)
grow
(
new_size
);
grow
(
new_size
);
size_
=
new_size
;
size_
=
new_size
;
}
}
// Reserves space to store at least capacity elements.
// Reserves space to store at least capacity elements.
void
reserve
(
std
::
size_t
capacity
)
{
void
reserve
(
std
::
size_t
capacity
)
{
if
(
capacity
>
capacity_
)
if
(
capacity
>
capacity_
)
grow
(
capacity
);
grow
(
capacity
);
}
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
clear
()
FMT_NOEXCEPT
{
size_
=
0
;
}
void
push_back
(
const
T
&
value
)
{
void
push_back
(
const
T
&
value
)
{
if
(
size_
==
capacity_
)
if
(
size_
==
capacity_
)
grow
(
size_
+
1
);
grow
(
size_
+
1
);
ptr_
[
size_
++
]
=
value
;
ptr_
[
size_
++
]
=
value
;
...
@@ -360,16 +381,19 @@ public:
...
@@ -360,16 +381,19 @@ public:
// Appends data to the end of the buffer.
// Appends data to the end of the buffer.
void
append
(
const
T
*
begin
,
const
T
*
end
);
void
append
(
const
T
*
begin
,
const
T
*
end
);
T
&
operator
[](
std
::
size_t
index
)
{
T
&
operator
[](
std
::
size_t
index
)
{
return
ptr_
[
index
];
return
ptr_
[
index
];
}
}
const
T
&
operator
[](
std
::
size_t
index
)
const
{
const
T
&
operator
[](
std
::
size_t
index
)
const
{
return
ptr_
[
index
];
return
ptr_
[
index
];
}
}
};
};
template
<
typename
T
>
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
;
std
::
ptrdiff_t
num_elements
=
end
-
begin
;
if
(
size_
+
num_elements
>
capacity_
)
if
(
size_
+
num_elements
>
capacity_
)
grow
(
size_
+
num_elements
);
grow
(
size_
+
num_elements
);
...
@@ -380,12 +404,14 @@ void Buffer<T>::append(const T *begin, const T *end) {
...
@@ -380,12 +404,14 @@ void Buffer<T>::append(const T *begin, const T *end) {
// A memory buffer for POD types with the first SIZE elements stored in
// A memory buffer for POD types with the first SIZE elements stored in
// the object itself.
// the object itself.
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
=
std
::
allocator
<
T
>
>
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
=
std
::
allocator
<
T
>
>
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
class
MemoryBuffer
:
private
Allocator
,
public
Buffer
<
T
>
{
private:
private:
T
data_
[
SIZE
];
T
data_
[
SIZE
];
// Free memory allocated by the buffer.
// Free memory allocated by the buffer.
void
free
()
{
void
free
()
{
if
(
this
->
ptr_
!=
data_
)
this
->
deallocate
(
this
->
ptr_
,
this
->
capacity_
);
if
(
this
->
ptr_
!=
data_
)
this
->
deallocate
(
this
->
ptr_
,
this
->
capacity_
);
}
}
...
@@ -395,24 +421,28 @@ protected:
...
@@ -395,24 +421,28 @@ protected:
public:
public:
explicit
MemoryBuffer
(
const
Allocator
&
alloc
=
Allocator
())
explicit
MemoryBuffer
(
const
Allocator
&
alloc
=
Allocator
())
:
Allocator
(
alloc
),
Buffer
<
T
>
(
data_
,
SIZE
)
{}
:
Allocator
(
alloc
),
Buffer
<
T
>
(
data_
,
SIZE
)
{}
~
MemoryBuffer
()
{
~
MemoryBuffer
()
{
free
();
free
();
}
}
#if FMT_USE_RVALUE_REFERENCES
#if FMT_USE_RVALUE_REFERENCES
private:
private:
// Move data from other to this buffer.
// Move data from other to this buffer.
void
move
(
MemoryBuffer
&
other
)
{
void
move
(
MemoryBuffer
&
other
)
{
Allocator
&
this_alloc
=
*
this
,
&
other_alloc
=
other
;
Allocator
&
this_alloc
=
*
this
,
&
other_alloc
=
other
;
this_alloc
=
std
::
move
(
other_alloc
);
this_alloc
=
std
::
move
(
other_alloc
);
this
->
size_
=
other
.
size_
;
this
->
size_
=
other
.
size_
;
this
->
capacity_
=
other
.
capacity_
;
this
->
capacity_
=
other
.
capacity_
;
if
(
other
.
ptr_
==
other
.
data_
)
{
if
(
other
.
ptr_
==
other
.
data_
)
{
this
->
ptr_
=
data_
;
this
->
ptr_
=
data_
;
std
::
copy
(
other
.
data_
,
std
::
copy
(
other
.
data_
,
other
.
data_
+
this
->
size_
,
make_ptr
(
data_
,
this
->
capacity_
));
other
.
data_
+
this
->
size_
,
make_ptr
(
data_
,
this
->
capacity_
));
}
}
else
{
else
{
this
->
ptr_
=
other
.
ptr_
;
this
->
ptr_
=
other
.
ptr_
;
// Set pointer to the inline array so that delete is not called
// Set pointer to the inline array so that delete is not called
// when freeing.
// when freeing.
...
@@ -421,11 +451,13 @@ private:
...
@@ -421,11 +451,13 @@ private:
}
}
public:
public:
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
MemoryBuffer
(
MemoryBuffer
&&
other
)
{
move
(
other
);
move
(
other
);
}
}
MemoryBuffer
&
operator
=
(
MemoryBuffer
&&
other
)
{
MemoryBuffer
&
operator
=
(
MemoryBuffer
&&
other
)
{
assert
(
this
!=
&
other
);
assert
(
this
!=
&
other
);
free
();
free
();
move
(
other
);
move
(
other
);
...
@@ -434,13 +466,15 @@ public:
...
@@ -434,13 +466,15 @@ public:
#endif
#endif
// Returns a copy of the allocator associated with this buffer.
// Returns a copy of the allocator associated with this buffer.
Allocator
get_allocator
()
const
{
Allocator
get_allocator
()
const
{
return
*
this
;
return
*
this
;
}
}
};
};
template
<
typename
T
,
std
::
size_t
SIZE
,
typename
Allocator
>
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
::
size_t
new_capacity
=
(
std
::
max
)(
size
,
this
->
capacity_
+
this
->
capacity_
/
2
);
(
std
::
max
)(
size
,
this
->
capacity_
+
this
->
capacity_
/
2
);
T
*
new_ptr
=
this
->
allocate
(
new_capacity
);
T
*
new_ptr
=
this
->
allocate
(
new_capacity
);
...
@@ -460,7 +494,8 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
...
@@ -460,7 +494,8 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
#ifndef _MSC_VER
#ifndef _MSC_VER
// Portable version of signbit.
// 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
// When compiled in C++11 mode signbit is no longer a macro but a function
// defined in namespace std and the macro is undefined.
// defined in namespace std and the macro is undefined.
# ifdef signbit
# ifdef signbit
...
@@ -472,22 +507,27 @@ inline int getsign(double x) {
...
@@ -472,22 +507,27 @@ inline int getsign(double x) {
// Portable version of isinf.
// Portable version of isinf.
# ifdef isinf
# ifdef isinf
inline
int
isinfinity
(
double
x
)
{
inline
int
isinfinity
(
double
x
)
{
return
isinf
(
x
);
return
isinf
(
x
);
}
}
inline
int
isinfinity
(
long
double
x
)
{
inline
int
isinfinity
(
long
double
x
)
{
return
isinf
(
x
);
return
isinf
(
x
);
}
}
# else
# else
inline
int
isinfinity
(
double
x
)
{
inline
int
isinfinity
(
double
x
)
{
return
std
::
isinf
(
x
);
return
std
::
isinf
(
x
);
}
}
inline
int
isinfinity
(
long
double
x
)
{
inline
int
isinfinity
(
long
double
x
)
{
return
std
::
isinf
(
x
);
return
std
::
isinf
(
x
);
}
}
# endif
# endif
#else
#else
inline
int
getsign
(
double
value
)
{
inline
int
getsign
(
double
value
)
{
if
(
value
<
0
)
return
1
;
if
(
value
<
0
)
return
1
;
if
(
value
==
value
)
return
0
;
if
(
value
==
value
)
return
0
;
int
dec
=
0
,
sign
=
0
;
int
dec
=
0
,
sign
=
0
;
...
@@ -495,16 +535,19 @@ inline int getsign(double value) {
...
@@ -495,16 +535,19 @@ inline int getsign(double value) {
_ecvt_s
(
buffer
,
sizeof
(
buffer
),
value
,
0
,
&
dec
,
&
sign
);
_ecvt_s
(
buffer
,
sizeof
(
buffer
),
value
,
0
,
&
dec
,
&
sign
);
return
sign
;
return
sign
;
}
}
inline
int
isinfinity
(
double
x
)
{
inline
int
isinfinity
(
double
x
)
{
return
!
_finite
(
x
);
return
!
_finite
(
x
);
}
}
inline
int
isinfinity
(
long
double
x
)
{
inline
int
isinfinity
(
long
double
x
)
{
return
!
_finite
(
static_cast
<
double
>
(
x
));
return
!
_finite
(
static_cast
<
double
>
(
x
));
}
}
#endif
#endif
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicCharTraits
{
class
BasicCharTraits
{
public:
public:
#if _SECURE_SCL
#if _SECURE_SCL
typedef
stdext
::
checked_array_iterator
<
Char
*>
CharPtr
;
typedef
stdext
::
checked_array_iterator
<
Char
*>
CharPtr
;
...
@@ -517,13 +560,15 @@ template <typename Char>
...
@@ -517,13 +560,15 @@ template <typename Char>
class
CharTraits
;
class
CharTraits
;
template
<
>
template
<
>
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
class
CharTraits
<
char
>
:
public
BasicCharTraits
<
char
>
{
private:
private:
// Conversion from wchar_t to char is not allowed.
// Conversion from wchar_t to char is not allowed.
static
char
convert
(
wchar_t
);
static
char
convert
(
wchar_t
);
public:
public:
static
char
convert
(
char
value
)
{
static
char
convert
(
char
value
)
{
return
value
;
return
value
;
}
}
...
@@ -534,12 +579,15 @@ public:
...
@@ -534,12 +579,15 @@ public:
};
};
template
<
>
template
<
>
class
CharTraits
<
wchar_t
>
:
public
BasicCharTraits
<
wchar_t
>
{
class
CharTraits
<
wchar_t
>
:
public
BasicCharTraits
<
wchar_t
>
{
public:
public:
static
wchar_t
convert
(
char
value
)
{
static
wchar_t
convert
(
char
value
)
{
return
value
;
return
value
;
}
}
static
wchar_t
convert
(
wchar_t
value
)
{
static
wchar_t
convert
(
wchar_t
value
)
{
return
value
;
return
value
;
}
}
...
@@ -550,17 +598,21 @@ public:
...
@@ -550,17 +598,21 @@ public:
// Checks if a number is negative - used to avoid warnings.
// Checks if a number is negative - used to avoid warnings.
template
<
bool
IsSigned
>
template
<
bool
IsSigned
>
struct
SignChecker
{
struct
SignChecker
{
template
<
typename
T
>
template
<
typename
T
>
static
bool
is_negative
(
T
value
)
{
static
bool
is_negative
(
T
value
)
{
return
value
<
0
;
return
value
<
0
;
}
}
};
};
template
<
>
template
<
>
struct
SignChecker
<
false
>
{
struct
SignChecker
<
false
>
{
template
<
typename
T
>
template
<
typename
T
>
static
bool
is_negative
(
T
)
{
static
bool
is_negative
(
T
)
{
return
false
;
return
false
;
}
}
};
};
...
@@ -568,23 +620,27 @@ struct SignChecker<false> {
...
@@ -568,23 +620,27 @@ struct SignChecker<false> {
// Returns true if value is negative, false otherwise.
// Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template
<
typename
T
>
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
);
return
SignChecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
is_negative
(
value
);
}
}
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
template
<
bool
FitsIn32Bits
>
template
<
bool
FitsIn32Bits
>
struct
TypeSelector
{
struct
TypeSelector
{
typedef
uint32_t
Type
;
typedef
uint32_t
Type
;
};
};
template
<
>
template
<
>
struct
TypeSelector
<
false
>
{
struct
TypeSelector
<
false
>
{
typedef
uint64_t
Type
;
typedef
uint64_t
Type
;
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
IntTraits
{
struct
IntTraits
{
// Smallest of uint32_t and uint64_t that is large enough to represent
// Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T.
// all values of T.
typedef
typename
typedef
typename
...
@@ -593,7 +649,8 @@ struct IntTraits {
...
@@ -593,7 +649,8 @@ struct IntTraits {
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template
<
typename
T
>
template
<
typename
T
>
struct
MakeUnsigned
{
struct
MakeUnsigned
{
typedef
T
Type
;
typedef
T
Type
;
};
};
...
@@ -613,7 +670,8 @@ void report_unknown_type(char code, const char *type);
...
@@ -613,7 +670,8 @@ void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// Static data is placed in this class template to allow header-only
// configuration.
// configuration.
template
<
typename
T
=
void
>
template
<
typename
T
=
void
>
struct
BasicData
{
struct
BasicData
{
static
const
uint32_t
POWERS_OF_10_32
[];
static
const
uint32_t
POWERS_OF_10_32
[];
static
const
uint64_t
POWERS_OF_10_64
[];
static
const
uint64_t
POWERS_OF_10_64
[];
static
const
char
DIGITS
[];
static
const
char
DIGITS
[];
...
@@ -632,7 +690,8 @@ typedef BasicData<> Data;
...
@@ -632,7 +690,8 @@ typedef BasicData<> Data;
#ifdef FMT_BUILTIN_CLZLL
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
// 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
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
unsigned
t
=
(
64
-
FMT_BUILTIN_CLZLL
(
n
|
1
))
*
1233
>>
12
;
unsigned
t
=
(
64
-
FMT_BUILTIN_CLZLL
(
n
|
1
))
*
1233
>>
12
;
...
@@ -640,9 +699,11 @@ inline unsigned count_digits(uint64_t n) {
...
@@ -640,9 +699,11 @@ inline unsigned count_digits(uint64_t n) {
}
}
#else
#else
// Fallback version of count_digits used when __builtin_clz is not available.
// 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
;
unsigned
count
=
1
;
for
(;;)
{
for
(;;)
{
// Integer division is slow so do it for a group of four digits instead
// 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
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
@@ -658,7 +719,8 @@ inline unsigned count_digits(uint64_t n) {
...
@@ -658,7 +719,8 @@ inline unsigned count_digits(uint64_t n) {
#ifdef FMT_BUILTIN_CLZ
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
// 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
;
uint32_t
t
=
(
32
-
FMT_BUILTIN_CLZ
(
n
|
1
))
*
1233
>>
12
;
return
t
-
(
n
<
Data
::
POWERS_OF_10_32
[
t
])
+
1
;
return
t
-
(
n
<
Data
::
POWERS_OF_10_32
[
t
])
+
1
;
}
}
...
@@ -666,9 +728,11 @@ inline unsigned count_digits(uint32_t n) {
...
@@ -666,9 +728,11 @@ inline unsigned count_digits(uint32_t n) {
// Formats a decimal unsigned integer value writing into buffer.
// Formats a decimal unsigned integer value writing into buffer.
template
<
typename
UInt
,
typename
Char
>
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
;
--
num_digits
;
while
(
value
>=
100
)
{
while
(
value
>=
100
)
{
// Integer division is slow so do it for a group of two digits instead
// 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
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
@@ -678,7 +742,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
...
@@ -678,7 +742,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
buffer
[
num_digits
-
1
]
=
Data
::
DIGITS
[
index
];
buffer
[
num_digits
-
1
]
=
Data
::
DIGITS
[
index
];
num_digits
-=
2
;
num_digits
-=
2
;
}
}
if
(
value
<
10
)
{
if
(
value
<
10
)
{
*
buffer
=
static_cast
<
char
>
(
'0'
+
value
);
*
buffer
=
static_cast
<
char
>
(
'0'
+
value
);
return
;
return
;
}
}
...
@@ -690,45 +755,55 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
...
@@ -690,45 +755,55 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
#ifdef _WIN32
#ifdef _WIN32
// A converter from UTF-8 to UTF-16.
// A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF8ToUTF16
{
class
UTF8ToUTF16
{
private:
private:
MemoryBuffer
<
wchar_t
,
INLINE_BUFFER_SIZE
>
buffer_
;
MemoryBuffer
<
wchar_t
,
INLINE_BUFFER_SIZE
>
buffer_
;
public:
public:
explicit
UTF8ToUTF16
(
StringRef
s
);
explicit
UTF8ToUTF16
(
StringRef
s
);
operator
WStringRef
()
const
{
operator
WStringRef
()
const
{
return
WStringRef
(
&
buffer_
[
0
],
size
());
return
WStringRef
(
&
buffer_
[
0
],
size
());
}
}
size_t
size
()
const
{
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
return
buffer_
.
size
()
-
1
;
}
}
const
wchar_t
*
c_str
()
const
{
const
wchar_t
*
c_str
()
const
{
return
&
buffer_
[
0
];
return
&
buffer_
[
0
];
}
}
std
::
wstring
str
()
const
{
std
::
wstring
str
()
const
{
return
std
::
wstring
(
&
buffer_
[
0
],
size
());
return
std
::
wstring
(
&
buffer_
[
0
],
size
());
}
}
};
};
// A converter from UTF-16 to UTF-8.
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
// It is only provided for Windows since other systems support UTF-8 natively.
class
UTF16ToUTF8
{
class
UTF16ToUTF8
{
private:
private:
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer_
;
MemoryBuffer
<
char
,
INLINE_BUFFER_SIZE
>
buffer_
;
public:
public:
UTF16ToUTF8
()
{}
UTF16ToUTF8
()
{}
explicit
UTF16ToUTF8
(
WStringRef
s
);
explicit
UTF16ToUTF8
(
WStringRef
s
);
operator
StringRef
()
const
{
operator
StringRef
()
const
{
return
StringRef
(
&
buffer_
[
0
],
size
());
return
StringRef
(
&
buffer_
[
0
],
size
());
}
}
size_t
size
()
const
{
size_t
size
()
const
{
return
buffer_
.
size
()
-
1
;
return
buffer_
.
size
()
-
1
;
}
}
const
char
*
c_str
()
const
{
const
char
*
c_str
()
const
{
return
&
buffer_
[
0
];
return
&
buffer_
[
0
];
}
}
std
::
string
str
()
const
{
std
::
string
str
()
const
{
return
std
::
string
(
&
buffer_
[
0
],
size
());
return
std
::
string
(
&
buffer_
[
0
],
size
());
}
}
...
@@ -750,20 +825,24 @@ void format_windows_error(fmt::Writer &out, int error_code,
...
@@ -750,20 +825,24 @@ void format_windows_error(fmt::Writer &out, int error_code,
// Computes max(Arg, 1) at compile time. It is used to avoid errors about
// Computes max(Arg, 1) at compile time. It is used to avoid errors about
// allocating an array of 0 size.
// allocating an array of 0 size.
template
<
unsigned
Arg
>
template
<
unsigned
Arg
>
struct
NonZero
{
struct
NonZero
{
enum
{
VALUE
=
Arg
};
enum
{
VALUE
=
Arg
};
};
};
template
<
>
template
<
>
struct
NonZero
<
0
>
{
struct
NonZero
<
0
>
{
enum
{
VALUE
=
1
};
enum
{
VALUE
=
1
};
};
};
// The value of a formatting argument. It is a POD type to allow storage in
// The value of a formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
// internal::MemoryBuffer.
struct
Value
{
struct
Value
{
template
<
typename
Char
>
template
<
typename
Char
>
struct
StringValue
{
struct
StringValue
{
const
Char
*
value
;
const
Char
*
value
;
std
::
size_t
size
;
std
::
size_t
size
;
};
};
...
@@ -771,12 +850,14 @@ struct Value {
...
@@ -771,12 +850,14 @@ struct Value {
typedef
void
(
*
FormatFunc
)(
typedef
void
(
*
FormatFunc
)(
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
);
void
*
formatter
,
const
void
*
arg
,
void
*
format_str_ptr
);
struct
CustomValue
{
struct
CustomValue
{
const
void
*
value
;
const
void
*
value
;
FormatFunc
format
;
FormatFunc
format
;
};
};
union
{
union
{
int
int_value
;
int
int_value
;
unsigned
uint_value
;
unsigned
uint_value
;
LongLong
long_long_value
;
LongLong
long_long_value
;
...
@@ -792,8 +873,10 @@ struct Value {
...
@@ -792,8 +873,10 @@ struct Value {
};
};
};
};
struct
Arg
:
Value
{
struct
Arg
:
Value
enum
Type
{
{
enum
Type
{
NONE
,
NONE
,
// Integer types should go first,
// Integer types should go first,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
INT
,
UINT
,
LONG_LONG
,
ULONG_LONG
,
CHAR
,
LAST_INTEGER_TYPE
=
CHAR
,
...
@@ -810,20 +893,23 @@ struct None {};
...
@@ -810,20 +893,23 @@ struct None {};
// A helper class template to enable or disable overloads taking wide
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
// characters and strings in MakeValue.
template
<
typename
T
,
typename
Char
>
template
<
typename
T
,
typename
Char
>
struct
WCharHelper
{
struct
WCharHelper
{
typedef
None
<
T
>
Supported
;
typedef
None
<
T
>
Supported
;
typedef
T
Unsupported
;
typedef
T
Unsupported
;
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
WCharHelper
<
T
,
wchar_t
>
{
struct
WCharHelper
<
T
,
wchar_t
>
{
typedef
T
Supported
;
typedef
T
Supported
;
typedef
None
<
T
>
Unsupported
;
typedef
None
<
T
>
Unsupported
;
};
};
// Makes a Value object from any type.
// Makes a Value object from any type.
template
<
typename
Char
>
template
<
typename
Char
>
class
MakeValue
:
public
Value
{
class
MakeValue
:
public
Value
{
private:
private:
// The following two methods are private to disallow formatting of
// The following two methods are private to disallow formatting of
// arbitrary pointers. If you want to output a pointer cast it to
// arbitrary pointers. If you want to output a pointer cast it to
...
@@ -845,12 +931,14 @@ private:
...
@@ -845,12 +931,14 @@ private:
MakeValue
(
typename
WCharHelper
<
const
std
::
wstring
&
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
const
std
::
wstring
&
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
WStringRef
,
Char
>::
Unsupported
);
MakeValue
(
typename
WCharHelper
<
WStringRef
,
Char
>::
Unsupported
);
void
set_string
(
StringRef
str
)
{
void
set_string
(
StringRef
str
)
{
string
.
value
=
str
.
c_str
();
string
.
value
=
str
.
c_str
();
string
.
size
=
str
.
size
();
string
.
size
=
str
.
size
();
}
}
void
set_string
(
WStringRef
str
)
{
void
set_string
(
WStringRef
str
)
{
wstring
.
value
=
str
.
c_str
();
wstring
.
value
=
str
.
c_str
();
wstring
.
size
=
str
.
size
();
wstring
.
size
=
str
.
size
();
}
}
...
@@ -858,7 +946,8 @@ private:
...
@@ -858,7 +946,8 @@ private:
// Formats an argument of a custom type, such as a user-defined class.
// Formats an argument of a custom type, such as a user-defined class.
template
<
typename
T
>
template
<
typename
T
>
static
void
format_custom_arg
(
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
),
format
(
*
static_cast
<
BasicFormatter
<
Char
>*>
(
formatter
),
*
static_cast
<
const
Char
**>
(
format_str_ptr
),
*
static_cast
<
const
Char
**>
(
format_str_ptr
),
*
static_cast
<
const
T
*>
(
arg
));
*
static_cast
<
const
T
*>
(
arg
));
...
@@ -877,7 +966,8 @@ public:
...
@@ -877,7 +966,8 @@ public:
FMT_MAKE_VALUE
(
int
,
int_value
,
INT
)
FMT_MAKE_VALUE
(
int
,
int_value
,
INT
)
FMT_MAKE_VALUE
(
unsigned
,
uint_value
,
UINT
)
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
// 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.
// translated either to int or to long long depending on its size.
if
(
sizeof
(
long
)
==
sizeof
(
int
))
if
(
sizeof
(
long
)
==
sizeof
(
int
))
...
@@ -885,17 +975,20 @@ public:
...
@@ -885,17 +975,20 @@ public:
else
else
long_long_value
=
value
;
long_long_value
=
value
;
}
}
static
uint64_t
type
(
long
)
{
static
uint64_t
type
(
long
)
{
return
sizeof
(
long
)
==
sizeof
(
int
)
?
Arg
::
INT
:
Arg
::
LONG_LONG
;
return
sizeof
(
long
)
==
sizeof
(
int
)
?
Arg
::
INT
:
Arg
::
LONG_LONG
;
}
}
MakeValue
(
unsigned
long
value
)
{
MakeValue
(
unsigned
long
value
)
{
if
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
))
if
(
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
))
uint_value
=
static_cast
<
unsigned
>
(
value
);
uint_value
=
static_cast
<
unsigned
>
(
value
);
else
else
ulong_long_value
=
value
;
ulong_long_value
=
value
;
}
}
static
uint64_t
type
(
unsigned
long
)
{
static
uint64_t
type
(
unsigned
long
)
{
return
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)
?
return
sizeof
(
unsigned
long
)
==
sizeof
(
unsigned
)
?
Arg
::
UINT
:
Arg
::
ULONG_LONG
;
Arg
::
UINT
:
Arg
::
ULONG_LONG
;
}
}
...
@@ -909,10 +1002,12 @@ public:
...
@@ -909,10 +1002,12 @@ public:
FMT_MAKE_VALUE
(
unsigned
char
,
int_value
,
CHAR
)
FMT_MAKE_VALUE
(
unsigned
char
,
int_value
,
CHAR
)
FMT_MAKE_VALUE
(
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
;
int_value
=
value
;
}
}
static
uint64_t
type
(
wchar_t
)
{
static
uint64_t
type
(
wchar_t
)
{
return
Arg
::
CHAR
;
return
Arg
::
CHAR
;
}
}
...
@@ -942,12 +1037,14 @@ public:
...
@@ -942,12 +1037,14 @@ public:
FMT_MAKE_VALUE
(
const
void
*
,
pointer
,
POINTER
)
FMT_MAKE_VALUE
(
const
void
*
,
pointer
,
POINTER
)
template
<
typename
T
>
template
<
typename
T
>
MakeValue
(
const
T
&
value
)
{
MakeValue
(
const
T
&
value
)
{
custom
.
value
=
&
value
;
custom
.
value
=
&
value
;
custom
.
format
=
&
format_custom_arg
<
T
>
;
custom
.
format
=
&
format_custom_arg
<
T
>
;
}
}
template
<
typename
T
>
template
<
typename
T
>
static
uint64_t
type
(
const
T
&
)
{
static
uint64_t
type
(
const
T
&
)
{
return
Arg
::
CUSTOM
;
return
Arg
::
CUSTOM
;
}
}
};
};
...
@@ -975,58 +1072,75 @@ public:
...
@@ -975,58 +1072,75 @@ public:
// ArgVisitor uses the curiously recurring template pattern:
// ArgVisitor uses the curiously recurring template pattern:
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template
<
typename
Impl
,
typename
Result
>
template
<
typename
Impl
,
typename
Result
>
class
ArgVisitor
{
class
ArgVisitor
{
public:
public:
Result
visit_unhandled_arg
()
{
Result
visit_unhandled_arg
()
{
return
Result
();
return
Result
();
}
}
Result
visit_int
(
int
value
)
{
Result
visit_int
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_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
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_uint
(
unsigned
value
)
{
Result
visit_uint
(
unsigned
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
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
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
Result
visit_char
(
int
value
)
{
Result
visit_char
(
int
value
)
{
return
FMT_DISPATCH
(
visit_any_int
(
value
));
return
FMT_DISPATCH
(
visit_any_int
(
value
));
}
}
template
<
typename
T
>
template
<
typename
T
>
Result
visit_any_int
(
T
)
{
Result
visit_any_int
(
T
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_double
(
double
value
)
{
Result
visit_double
(
double
value
)
{
return
FMT_DISPATCH
(
visit_any_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
));
return
FMT_DISPATCH
(
visit_any_double
(
value
));
}
}
template
<
typename
T
>
template
<
typename
T
>
Result
visit_any_double
(
T
)
{
Result
visit_any_double
(
T
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_string
(
Arg
::
StringValue
<
char
>
)
{
Result
visit_string
(
Arg
::
StringValue
<
char
>
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
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
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_pointer
(
const
void
*
)
{
Result
visit_pointer
(
const
void
*
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit_custom
(
Arg
::
CustomValue
)
{
Result
visit_custom
(
Arg
::
CustomValue
)
{
return
FMT_DISPATCH
(
visit_unhandled_arg
());
return
FMT_DISPATCH
(
visit_unhandled_arg
());
}
}
Result
visit
(
const
Arg
&
arg
)
{
Result
visit
(
const
Arg
&
arg
)
switch
(
arg
.
type
)
{
{
switch
(
arg
.
type
)
{
default:
default:
assert
(
false
);
assert
(
false
);
return
Result
();
return
Result
();
...
@@ -1044,7 +1158,8 @@ public:
...
@@ -1044,7 +1158,8 @@ public:
return
FMT_DISPATCH
(
visit_long_double
(
arg
.
long_double_value
));
return
FMT_DISPATCH
(
visit_long_double
(
arg
.
long_double_value
));
case
Arg
:
:
CHAR
:
case
Arg
:
:
CHAR
:
return
FMT_DISPATCH
(
visit_char
(
arg
.
int_value
));
return
FMT_DISPATCH
(
visit_char
(
arg
.
int_value
));
case
Arg
:
:
CSTRING
:
{
case
Arg
:
:
CSTRING
:
{
Value
::
StringValue
<
char
>
str
=
arg
.
string
;
Value
::
StringValue
<
char
>
str
=
arg
.
string
;
str
.
size
=
0
;
str
.
size
=
0
;
return
FMT_DISPATCH
(
visit_string
(
str
));
return
FMT_DISPATCH
(
visit_string
(
str
));
...
@@ -1061,7 +1176,8 @@ public:
...
@@ -1061,7 +1176,8 @@ public:
}
}
};
};
class
RuntimeError
:
public
std
::
runtime_error
{
class
RuntimeError
:
public
std
::
runtime_error
{
protected:
protected:
RuntimeError
()
:
std
::
runtime_error
(
""
)
{}
RuntimeError
()
:
std
::
runtime_error
(
""
)
{}
};
};
...
@@ -1073,7 +1189,8 @@ class ArgFormatter;
...
@@ -1073,7 +1189,8 @@ class ArgFormatter;
/**
/**
An argument list.
An argument list.
*/
*/
class
ArgList
{
class
ArgList
{
private:
private:
uint64_t
types_
;
uint64_t
types_
;
const
internal
::
Value
*
values_
;
const
internal
::
Value
*
values_
;
...
@@ -1089,10 +1206,12 @@ public:
...
@@ -1089,10 +1206,12 @@ public:
/**
/**
Returns the argument at specified index.
Returns the argument at specified index.
*/
*/
internal
::
Arg
operator
[](
unsigned
index
)
const
{
internal
::
Arg
operator
[](
unsigned
index
)
const
{
using
internal
::
Arg
;
using
internal
::
Arg
;
Arg
arg
;
Arg
arg
;
if
(
index
>=
MAX_ARGS
)
{
if
(
index
>=
MAX_ARGS
)
{
arg
.
type
=
Arg
::
NONE
;
arg
.
type
=
Arg
::
NONE
;
return
arg
;
return
arg
;
}
}
...
@@ -1101,7 +1220,8 @@ public:
...
@@ -1101,7 +1220,8 @@ public:
Arg
::
Type
type
=
Arg
::
Type
type
=
static_cast
<
Arg
::
Type
>
((
types_
&
(
mask
<<
shift
))
>>
shift
);
static_cast
<
Arg
::
Type
>
((
types_
&
(
mask
<<
shift
))
>>
shift
);
arg
.
type
=
type
;
arg
.
type
=
type
;
if
(
type
!=
Arg
::
NONE
)
{
if
(
type
!=
Arg
::
NONE
)
{
internal
::
Value
&
value
=
arg
;
internal
::
Value
&
value
=
arg
;
value
=
values_
[
index
];
value
=
values_
[
index
];
}
}
...
@@ -1111,9 +1231,11 @@ public:
...
@@ -1111,9 +1231,11 @@ public:
struct
FormatSpec
;
struct
FormatSpec
;
namespace
internal
{
namespace
internal
{
class
FormatterBase
{
class
FormatterBase
{
private:
private:
ArgList
args_
;
ArgList
args_
;
int
next_arg_index_
;
int
next_arg_index_
;
...
@@ -1122,7 +1244,8 @@ private:
...
@@ -1122,7 +1244,8 @@ private:
Arg
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
Arg
do_get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
protected:
protected:
void
set_args
(
const
ArgList
&
args
)
{
void
set_args
(
const
ArgList
&
args
)
{
args_
=
args
;
args_
=
args
;
next_arg_index_
=
0
;
next_arg_index_
=
0
;
}
}
...
@@ -1135,7 +1258,8 @@ protected:
...
@@ -1135,7 +1258,8 @@ protected:
Arg
get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
Arg
get_arg
(
unsigned
arg_index
,
const
char
*&
error
);
template
<
typename
Char
>
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
)
if
(
start
!=
end
)
w
<<
BasicStringRef
<
Char
>
(
start
,
end
-
start
);
w
<<
BasicStringRef
<
Char
>
(
start
,
end
-
start
);
}
}
...
@@ -1143,7 +1267,8 @@ protected:
...
@@ -1143,7 +1267,8 @@ protected:
// A printf formatter.
// A printf formatter.
template
<
typename
Char
>
template
<
typename
Char
>
class
PrintfFormatter
:
private
FormatterBase
{
class
PrintfFormatter
:
private
FormatterBase
{
private:
private:
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
...
@@ -1163,7 +1288,8 @@ public:
...
@@ -1163,7 +1288,8 @@ public:
// A formatter.
// A formatter.
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicFormatter
:
private
internal
::
FormatterBase
{
class
BasicFormatter
:
private
internal
::
FormatterBase
{
private:
private:
BasicWriter
<
Char
>
&
writer_
;
BasicWriter
<
Char
>
&
writer_
;
const
Char
*
start_
;
const
Char
*
start_
;
...
@@ -1176,7 +1302,8 @@ private:
...
@@ -1176,7 +1302,8 @@ private:
public:
public:
explicit
BasicFormatter
(
BasicWriter
<
Char
>
&
w
)
:
writer_
(
w
)
{}
explicit
BasicFormatter
(
BasicWriter
<
Char
>
&
w
)
:
writer_
(
w
)
{}
BasicWriter
<
Char
>
&
writer
()
{
BasicWriter
<
Char
>
&
writer
()
{
return
writer_
;
return
writer_
;
}
}
...
@@ -1185,12 +1312,14 @@ public:
...
@@ -1185,12 +1312,14 @@ public:
const
Char
*
format
(
const
Char
*&
format_str
,
const
internal
::
Arg
&
arg
);
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
ALIGN_DEFAULT
,
ALIGN_LEFT
,
ALIGN_RIGHT
,
ALIGN_CENTER
,
ALIGN_NUMERIC
};
};
// Flags.
// Flags.
enum
{
enum
{
SIGN_FLAG
=
1
,
PLUS_FLAG
=
2
,
MINUS_FLAG
=
4
,
HASH_FLAG
=
8
,
SIGN_FLAG
=
1
,
PLUS_FLAG
=
2
,
MINUS_FLAG
=
4
,
HASH_FLAG
=
8
,
CHAR_FLAG
=
0x10
// Argument has char type - used in error reporting.
CHAR_FLAG
=
0x10
// Argument has char type - used in error reporting.
};
};
...
@@ -1200,29 +1329,37 @@ struct EmptySpec {};
...
@@ -1200,29 +1329,37 @@ struct EmptySpec {};
// A type specifier.
// A type specifier.
template
<
char
TYPE
>
template
<
char
TYPE
>
struct
TypeSpec
:
EmptySpec
{
struct
TypeSpec
:
EmptySpec
Alignment
align
()
const
{
{
Alignment
align
()
const
{
return
ALIGN_DEFAULT
;
return
ALIGN_DEFAULT
;
}
}
unsigned
width
()
const
{
unsigned
width
()
const
{
return
0
;
return
0
;
}
}
int
precision
()
const
{
int
precision
()
const
{
return
-
1
;
return
-
1
;
}
}
bool
flag
(
unsigned
)
const
{
bool
flag
(
unsigned
)
const
{
return
false
;
return
false
;
}
}
char
type
()
const
{
char
type
()
const
{
return
TYPE
;
return
TYPE
;
}
}
char
fill
()
const
{
char
fill
()
const
{
return
' '
;
return
' '
;
}
}
};
};
// A width specifier.
// A width specifier.
struct
WidthSpec
{
struct
WidthSpec
{
unsigned
width_
;
unsigned
width_
;
// Fill is always wchar_t and cast to char if necessary to avoid having
// Fill is always wchar_t and cast to char if necessary to avoid having
// two specialization of WidthSpec and its subclasses.
// two specialization of WidthSpec and its subclasses.
...
@@ -1230,45 +1367,54 @@ struct WidthSpec {
...
@@ -1230,45 +1367,54 @@ struct WidthSpec {
WidthSpec
(
unsigned
width
,
wchar_t
fill
)
:
width_
(
width
),
fill_
(
fill
)
{}
WidthSpec
(
unsigned
width
,
wchar_t
fill
)
:
width_
(
width
),
fill_
(
fill
)
{}
unsigned
width
()
const
{
unsigned
width
()
const
{
return
width_
;
return
width_
;
}
}
wchar_t
fill
()
const
{
wchar_t
fill
()
const
{
return
fill_
;
return
fill_
;
}
}
};
};
// An alignment specifier.
// An alignment specifier.
struct
AlignSpec
:
WidthSpec
{
struct
AlignSpec
:
WidthSpec
{
Alignment
align_
;
Alignment
align_
;
AlignSpec
(
unsigned
width
,
wchar_t
fill
,
Alignment
align
=
ALIGN_DEFAULT
)
AlignSpec
(
unsigned
width
,
wchar_t
fill
,
Alignment
align
=
ALIGN_DEFAULT
)
:
WidthSpec
(
width
,
fill
),
align_
(
align
)
{}
:
WidthSpec
(
width
,
fill
),
align_
(
align
)
{}
Alignment
align
()
const
{
Alignment
align
()
const
{
return
align_
;
return
align_
;
}
}
int
precision
()
const
{
int
precision
()
const
{
return
-
1
;
return
-
1
;
}
}
};
};
// An alignment and type specifier.
// An alignment and type specifier.
template
<
char
TYPE
>
template
<
char
TYPE
>
struct
AlignTypeSpec
:
AlignSpec
{
struct
AlignTypeSpec
:
AlignSpec
{
AlignTypeSpec
(
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
)
{}
AlignTypeSpec
(
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
)
{}
bool
flag
(
unsigned
)
const
{
bool
flag
(
unsigned
)
const
{
return
false
;
return
false
;
}
}
char
type
()
const
{
char
type
()
const
{
return
TYPE
;
return
TYPE
;
}
}
};
};
// A full format specifier.
// A full format specifier.
struct
FormatSpec
:
AlignSpec
{
struct
FormatSpec
:
AlignSpec
{
unsigned
flags_
;
unsigned
flags_
;
int
precision_
;
int
precision_
;
char
type_
;
char
type_
;
...
@@ -1277,20 +1423,24 @@ struct FormatSpec : AlignSpec {
...
@@ -1277,20 +1423,24 @@ struct FormatSpec : AlignSpec {
unsigned
width
=
0
,
char
type
=
0
,
wchar_t
fill
=
' '
)
unsigned
width
=
0
,
char
type
=
0
,
wchar_t
fill
=
' '
)
:
AlignSpec
(
width
,
fill
),
flags_
(
0
),
precision_
(
-
1
),
type_
(
type
)
{}
:
AlignSpec
(
width
,
fill
),
flags_
(
0
),
precision_
(
-
1
),
type_
(
type
)
{}
bool
flag
(
unsigned
f
)
const
{
bool
flag
(
unsigned
f
)
const
{
return
(
flags_
&
f
)
!=
0
;
return
(
flags_
&
f
)
!=
0
;
}
}
int
precision
()
const
{
int
precision
()
const
{
return
precision_
;
return
precision_
;
}
}
char
type
()
const
{
char
type
()
const
{
return
type_
;
return
type_
;
}
}
};
};
// An integer format specifier.
// An integer format specifier.
template
<
typename
T
,
typename
SpecT
=
TypeSpec
<
0
>,
typename
Char
=
char
>
template
<
typename
T
,
typename
SpecT
=
TypeSpec
<
0
>,
typename
Char
=
char
>
class
IntFormatSpec
:
public
SpecT
{
class
IntFormatSpec
:
public
SpecT
{
private:
private:
T
value_
;
T
value_
;
...
@@ -1298,14 +1448,16 @@ public:
...
@@ -1298,14 +1448,16 @@ public:
IntFormatSpec
(
T
val
,
const
SpecT
&
spec
=
SpecT
())
IntFormatSpec
(
T
val
,
const
SpecT
&
spec
=
SpecT
())
:
SpecT
(
spec
),
value_
(
val
)
{}
:
SpecT
(
spec
),
value_
(
val
)
{}
T
value
()
const
{
T
value
()
const
{
return
value_
;
return
value_
;
}
}
};
};
// A string format specifier.
// A string format specifier.
template
<
typename
T
>
template
<
typename
T
>
class
StrFormatSpec
:
public
AlignSpec
{
class
StrFormatSpec
:
public
AlignSpec
{
private:
private:
const
T
*
str_
;
const
T
*
str_
;
...
@@ -1313,7 +1465,8 @@ public:
...
@@ -1313,7 +1465,8 @@ public:
StrFormatSpec
(
const
T
*
str
,
unsigned
width
,
wchar_t
fill
)
StrFormatSpec
(
const
T
*
str
,
unsigned
width
,
wchar_t
fill
)
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{}
:
AlignSpec
(
width
,
fill
),
str_
(
str
)
{}
const
T
*
str
()
const
{
const
T
*
str
()
const
{
return
str_
;
return
str_
;
}
}
};
};
...
@@ -1428,12 +1581,14 @@ std::string s = str(MemoryWriter() << pad("abc", 8));
...
@@ -1428,12 +1581,14 @@ std::string s = str(MemoryWriter() << pad("abc", 8));
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
inline
StrFormatSpec
<
Char
>
pad
(
inline
StrFormatSpec
<
Char
>
pad
(
const
Char
*
str
,
unsigned
width
,
Char
fill
=
' '
)
{
const
Char
*
str
,
unsigned
width
,
Char
fill
=
' '
)
{
return
StrFormatSpec
<
Char
>
(
str
,
width
,
fill
);
return
StrFormatSpec
<
Char
>
(
str
,
width
,
fill
);
}
}
inline
StrFormatSpec
<
wchar_t
>
pad
(
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
);
return
StrFormatSpec
<
wchar_t
>
(
str
,
width
,
fill
);
}
}
...
@@ -1456,24 +1611,29 @@ inline StrFormatSpec<wchar_t> pad(
...
@@ -1456,24 +1611,29 @@ inline StrFormatSpec<wchar_t> pad(
# define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace
internal
{
namespace
internal
inline
uint64_t
make_type
()
{
{
inline
uint64_t
make_type
()
{
return
0
;
return
0
;
}
}
template
<
typename
T
>
template
<
typename
T
>
inline
uint64_t
make_type
(
const
T
&
arg
)
{
inline
uint64_t
make_type
(
const
T
&
arg
)
{
return
MakeValue
<
char
>::
type
(
arg
);
return
MakeValue
<
char
>::
type
(
arg
);
}
}
#if FMT_USE_VARIADIC_TEMPLATES
#if FMT_USE_VARIADIC_TEMPLATES
template
<
typename
Arg
,
typename
...
Args
>
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
);
return
make_type
(
first
)
|
(
make_type
(
tail
...)
<<
4
);
}
}
#else
#else
struct
ArgType
{
struct
ArgType
{
uint64_t
type
;
uint64_t
type
;
ArgType
()
:
type
(
0
)
{}
ArgType
()
:
type
(
0
)
{}
...
@@ -1484,7 +1644,8 @@ struct ArgType {
...
@@ -1484,7 +1644,8 @@ struct ArgType {
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = 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
)
|
return
t0
.
type
|
(
t1
.
type
<<
4
)
|
(
t2
.
type
<<
8
)
|
(
t3
.
type
<<
12
)
|
(
t4
.
type
<<
16
)
|
(
t5
.
type
<<
20
)
|
(
t6
.
type
<<
24
)
|
(
t7
.
type
<<
28
)
|
(
t4
.
type
<<
16
)
|
(
t5
.
type
<<
20
)
|
(
t6
.
type
<<
24
)
|
(
t7
.
type
<<
28
)
|
(
t8
.
type
<<
32
)
|
(
t9
.
type
<<
36
)
|
(
t10
.
type
<<
40
)
|
(
t11
.
type
<<
44
)
|
(
t8
.
type
<<
32
)
|
(
t9
.
type
<<
36
)
|
(
t10
.
type
<<
40
)
|
(
t11
.
type
<<
44
)
|
...
@@ -1595,7 +1756,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
...
@@ -1595,7 +1756,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
An error returned by an operating system or a language runtime,
An error returned by an operating system or a language runtime,
for example a file opening error.
for example a file opening error.
*/
*/
class
SystemError
:
public
internal
::
RuntimeError
{
class
SystemError
:
public
internal
::
RuntimeError
{
private:
private:
void
init
(
int
err_code
,
StringRef
format_str
,
ArgList
args
);
void
init
(
int
err_code
,
StringRef
format_str
,
ArgList
args
);
...
@@ -1632,12 +1794,14 @@ public:
...
@@ -1632,12 +1794,14 @@ public:
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst
\endrst
*/
*/
SystemError
(
int
error_code
,
StringRef
message
)
{
SystemError
(
int
error_code
,
StringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
init
(
error_code
,
message
,
ArgList
());
}
}
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
StringRef
)
FMT_VARIADIC_CTOR
(
SystemError
,
init
,
int
,
StringRef
)
int
error_code
()
const
{
int
error_code
()
const
{
return
error_code_
;
return
error_code_
;
}
}
};
};
...
@@ -1661,7 +1825,8 @@ You can use one of the following typedefs for common character types:
...
@@ -1661,7 +1825,8 @@ You can use one of the following typedefs for common character types:
\endrst
\endrst
*/
*/
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicWriter
{
class
BasicWriter
{
private:
private:
// Output buffer.
// Output buffer.
internal
::
Buffer
<
Char
>
&
buffer_
;
internal
::
Buffer
<
Char
>
&
buffer_
;
...
@@ -1672,11 +1837,13 @@ private:
...
@@ -1672,11 +1837,13 @@ private:
#if _SECURE_SCL
#if _SECURE_SCL
// Returns pointer value.
// Returns pointer value.
static
Char
*
get
(
CharPtr
p
)
{
static
Char
*
get
(
CharPtr
p
)
{
return
p
.
base
();
return
p
.
base
();
}
}
#else
#else
static
Char
*
get
(
Char
*
p
)
{
static
Char
*
get
(
Char
*
p
)
{
return
p
;
return
p
;
}
}
#endif
#endif
...
@@ -1688,7 +1855,8 @@ private:
...
@@ -1688,7 +1855,8 @@ private:
// Grows the buffer by n characters and returns a pointer to the newly
// Grows the buffer by n characters and returns a pointer to the newly
// allocated area.
// allocated area.
CharPtr
grow_buffer
(
std
::
size_t
n
)
{
CharPtr
grow_buffer
(
std
::
size_t
n
)
{
std
::
size_t
size
=
buffer_
.
size
();
std
::
size_t
size
=
buffer_
.
size
();
buffer_
.
resize
(
size
+
n
);
buffer_
.
resize
(
size
+
n
);
return
internal
::
make_ptr
(
&
buffer_
[
size
],
n
);
return
internal
::
make_ptr
(
&
buffer_
[
size
],
n
);
...
@@ -1696,7 +1864,8 @@ private:
...
@@ -1696,7 +1864,8 @@ private:
// Prepare a buffer for integer formatting.
// Prepare a buffer for integer formatting.
CharPtr
prepare_int_buffer
(
unsigned
num_digits
,
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
;
unsigned
size
=
prefix_size
+
num_digits
;
CharPtr
p
=
grow_buffer
(
size
);
CharPtr
p
=
grow_buffer
(
size
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
...
@@ -1734,7 +1903,8 @@ private:
...
@@ -1734,7 +1903,8 @@ private:
// Appends floating-point length specifier to the format string.
// Appends floating-point length specifier to the format string.
// The second argument is only used for overload resolution.
// 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'
;
*
format_ptr
++
=
'L'
;
}
}
...
@@ -1759,7 +1929,8 @@ public:
...
@@ -1759,7 +1929,8 @@ public:
/**
/**
Returns the total number of characters written.
Returns the total number of characters written.
*/
*/
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
buffer_
.
size
();
return
buffer_
.
size
();
}
}
...
@@ -1767,7 +1938,8 @@ public:
...
@@ -1767,7 +1938,8 @@ public:
Returns a pointer to the output buffer content. No terminating null
Returns a pointer to the output buffer content. No terminating null
character is appended.
character is appended.
*/
*/
const
Char
*
data
()
const
FMT_NOEXCEPT
{
const
Char
*
data
()
const
FMT_NOEXCEPT
{
return
&
buffer_
[
0
];
return
&
buffer_
[
0
];
}
}
...
@@ -1775,7 +1947,8 @@ public:
...
@@ -1775,7 +1947,8 @@ public:
Returns a pointer to the output buffer content with terminating null
Returns a pointer to the output buffer content with terminating null
character appended.
character appended.
*/
*/
const
Char
*
c_str
()
const
{
const
Char
*
c_str
()
const
{
std
::
size_t
size
=
buffer_
.
size
();
std
::
size_t
size
=
buffer_
.
size
();
buffer_
.
reserve
(
size
+
1
);
buffer_
.
reserve
(
size
+
1
);
buffer_
[
size
]
=
'\0'
;
buffer_
[
size
]
=
'\0'
;
...
@@ -1785,7 +1958,8 @@ public:
...
@@ -1785,7 +1958,8 @@ public:
/**
/**
Returns the content of the output buffer as an `std::string`.
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
());
return
std
::
basic_string
<
Char
>
(
&
buffer_
[
0
],
buffer_
.
size
());
}
}
...
@@ -1814,35 +1988,43 @@ public:
...
@@ -1814,35 +1988,43 @@ public:
See also :ref:`syntax`.
See also :ref:`syntax`.
\endrst
\endrst
*/
*/
void
write
(
BasicStringRef
<
Char
>
format
,
ArgList
args
)
{
void
write
(
BasicStringRef
<
Char
>
format
,
ArgList
args
)
{
BasicFormatter
<
Char
>
(
*
this
).
format
(
format
,
args
);
BasicFormatter
<
Char
>
(
*
this
).
format
(
format
,
args
);
}
}
FMT_VARIADIC_VOID
(
write
,
BasicStringRef
<
Char
>
)
FMT_VARIADIC_VOID
(
write
,
BasicStringRef
<
Char
>
)
BasicWriter
&
operator
<<
(
int
value
)
{
BasicWriter
&
operator
<<
(
int
value
)
{
return
*
this
<<
IntFormatSpec
<
int
>
(
value
);
return
*
this
<<
IntFormatSpec
<
int
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
unsigned
value
)
{
BasicWriter
&
operator
<<
(
unsigned
value
)
{
return
*
this
<<
IntFormatSpec
<
unsigned
>
(
value
);
return
*
this
<<
IntFormatSpec
<
unsigned
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
long
value
)
{
BasicWriter
&
operator
<<
(
long
value
)
{
return
*
this
<<
IntFormatSpec
<
long
>
(
value
);
return
*
this
<<
IntFormatSpec
<
long
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
unsigned
long
value
)
{
BasicWriter
&
operator
<<
(
unsigned
long
value
)
{
return
*
this
<<
IntFormatSpec
<
unsigned
long
>
(
value
);
return
*
this
<<
IntFormatSpec
<
unsigned
long
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
LongLong
value
)
{
BasicWriter
&
operator
<<
(
LongLong
value
)
{
return
*
this
<<
IntFormatSpec
<
LongLong
>
(
value
);
return
*
this
<<
IntFormatSpec
<
LongLong
>
(
value
);
}
}
/**
/**
Formats *value* and writes it to the stream.
Formats *value* and writes it to the stream.
*/
*/
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
BasicWriter
&
operator
<<
(
ULongLong
value
)
{
return
*
this
<<
IntFormatSpec
<
ULongLong
>
(
value
);
return
*
this
<<
IntFormatSpec
<
ULongLong
>
(
value
);
}
}
BasicWriter
&
operator
<<
(
double
value
)
{
BasicWriter
&
operator
<<
(
double
value
)
{
write_double
(
value
,
FormatSpec
());
write_double
(
value
,
FormatSpec
());
return
*
this
;
return
*
this
;
}
}
...
@@ -1851,7 +2033,8 @@ public:
...
@@ -1851,7 +2033,8 @@ public:
Formats *value* using the general format for floating-point numbers
Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream.
(``'g'``) and writes it to the stream.
*/
*/
BasicWriter
&
operator
<<
(
long
double
value
)
{
BasicWriter
&
operator
<<
(
long
double
value
)
{
write_double
(
value
,
FormatSpec
());
write_double
(
value
,
FormatSpec
());
return
*
this
;
return
*
this
;
}
}
...
@@ -1859,13 +2042,15 @@ public:
...
@@ -1859,13 +2042,15 @@ public:
/**
/**
Writes a character to the stream.
Writes a character to the stream.
*/
*/
BasicWriter
&
operator
<<
(
char
value
)
{
BasicWriter
&
operator
<<
(
char
value
)
{
buffer_
.
push_back
(
value
);
buffer_
.
push_back
(
value
);
return
*
this
;
return
*
this
;
}
}
BasicWriter
&
operator
<<
(
BasicWriter
&
operator
<<
(
typename
internal
::
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
typename
internal
::
WCharHelper
<
wchar_t
,
Char
>::
Supported
value
)
{
buffer_
.
push_back
(
value
);
buffer_
.
push_back
(
value
);
return
*
this
;
return
*
this
;
}
}
...
@@ -1873,50 +2058,59 @@ public:
...
@@ -1873,50 +2058,59 @@ public:
/**
/**
Writes *value* to the stream.
Writes *value* to the stream.
*/
*/
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
BasicWriter
&
operator
<<
(
fmt
::
BasicStringRef
<
Char
>
value
)
{
const
Char
*
str
=
value
.
c_str
();
const
Char
*
str
=
value
.
c_str
();
buffer_
.
append
(
str
,
str
+
value
.
size
());
buffer_
.
append
(
str
,
str
+
value
.
size
());
return
*
this
;
return
*
this
;
}
}
template
<
typename
T
,
typename
Spec
,
typename
FillChar
>
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
());
internal
::
CharTraits
<
Char
>::
convert
(
FillChar
());
write_int
(
spec
.
value
(),
spec
);
write_int
(
spec
.
value
(),
spec
);
return
*
this
;
return
*
this
;
}
}
template
<
typename
StrChar
>
template
<
typename
StrChar
>
BasicWriter
&
operator
<<
(
const
StrFormatSpec
<
StrChar
>
&
spec
)
{
BasicWriter
&
operator
<<
(
const
StrFormatSpec
<
StrChar
>
&
spec
)
{
const
StrChar
*
s
=
spec
.
str
();
const
StrChar
*
s
=
spec
.
str
();
// TODO: error if fill is not convertible to Char
// TODO: error if fill is not convertible to Char
write_str
(
s
,
std
::
char_traits
<
Char
>::
length
(
s
),
spec
);
write_str
(
s
,
std
::
char_traits
<
Char
>::
length
(
s
),
spec
);
return
*
this
;
return
*
this
;
}
}
void
clear
()
FMT_NOEXCEPT
{
buffer_
.
clear
();
}
void
clear
()
FMT_NOEXCEPT
{
buffer_
.
clear
();
}
};
};
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
StrChar
>
template
<
typename
StrChar
>
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
write_str
(
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
();
CharPtr
out
=
CharPtr
();
if
(
spec
.
width
()
>
size
)
{
if
(
spec
.
width
()
>
size
)
{
out
=
grow_buffer
(
spec
.
width
());
out
=
grow_buffer
(
spec
.
width
());
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
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
);
std
::
fill_n
(
out
,
spec
.
width
()
-
size
,
fill
);
out
+=
spec
.
width
()
-
size
;
out
+=
spec
.
width
()
-
size
;
}
}
else
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
else
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
out
=
fill_padding
(
out
,
spec
.
width
(),
size
,
fill
);
out
=
fill_padding
(
out
,
spec
.
width
(),
size
,
fill
);
}
}
else
{
else
{
std
::
fill_n
(
out
+
size
,
spec
.
width
()
-
size
,
fill
);
std
::
fill_n
(
out
+
size
,
spec
.
width
()
-
size
,
fill
);
}
}
}
}
else
{
else
{
out
=
grow_buffer
(
size
);
out
=
grow_buffer
(
size
);
}
}
std
::
copy
(
s
,
s
+
size
,
out
);
std
::
copy
(
s
,
s
+
size
,
out
);
...
@@ -1927,7 +2121,8 @@ template <typename Char>
...
@@ -1927,7 +2121,8 @@ template <typename Char>
typename
BasicWriter
<
Char
>::
CharPtr
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
fill_padding
(
BasicWriter
<
Char
>::
fill_padding
(
CharPtr
buffer
,
unsigned
total_size
,
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
padding
=
total_size
-
content_size
;
std
::
size_t
left_padding
=
padding
/
2
;
std
::
size_t
left_padding
=
padding
/
2
;
Char
fill_char
=
static_cast
<
Char
>
(
fill
);
Char
fill_char
=
static_cast
<
Char
>
(
fill
);
...
@@ -1943,11 +2138,13 @@ template <typename Spec>
...
@@ -1943,11 +2138,13 @@ template <typename Spec>
typename
BasicWriter
<
Char
>::
CharPtr
typename
BasicWriter
<
Char
>::
CharPtr
BasicWriter
<
Char
>::
prepare_int_buffer
(
BasicWriter
<
Char
>::
prepare_int_buffer
(
unsigned
num_digits
,
const
Spec
&
spec
,
unsigned
num_digits
,
const
Spec
&
spec
,
const
char
*
prefix
,
unsigned
prefix_size
)
{
const
char
*
prefix
,
unsigned
prefix_size
)
{
unsigned
width
=
spec
.
width
();
unsigned
width
=
spec
.
width
();
Alignment
align
=
spec
.
align
();
Alignment
align
=
spec
.
align
();
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
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
// Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified.
// is specified.
if
(
prefix_size
>
0
&&
prefix
[
prefix_size
-
1
]
==
'0'
)
if
(
prefix_size
>
0
&&
prefix
[
prefix_size
-
1
]
==
'0'
)
...
@@ -1958,44 +2155,53 @@ BasicWriter<Char>::prepare_int_buffer(
...
@@ -1958,44 +2155,53 @@ BasicWriter<Char>::prepare_int_buffer(
return
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
return
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
buffer_
.
reserve
(
width
);
buffer_
.
reserve
(
width
);
unsigned
fill_size
=
width
-
number_size
;
unsigned
fill_size
=
width
-
number_size
;
if
(
align
!=
ALIGN_LEFT
)
{
if
(
align
!=
ALIGN_LEFT
)
{
CharPtr
p
=
grow_buffer
(
fill_size
);
CharPtr
p
=
grow_buffer
(
fill_size
);
std
::
fill
(
p
,
p
+
fill_size
,
fill
);
std
::
fill
(
p
,
p
+
fill_size
,
fill
);
}
}
CharPtr
result
=
prepare_int_buffer
(
CharPtr
result
=
prepare_int_buffer
(
num_digits
,
subspec
,
prefix
,
prefix_size
);
num_digits
,
subspec
,
prefix
,
prefix_size
);
if
(
align
==
ALIGN_LEFT
)
{
if
(
align
==
ALIGN_LEFT
)
{
CharPtr
p
=
grow_buffer
(
fill_size
);
CharPtr
p
=
grow_buffer
(
fill_size
);
std
::
fill
(
p
,
p
+
fill_size
,
fill
);
std
::
fill
(
p
,
p
+
fill_size
,
fill
);
}
}
return
result
;
return
result
;
}
}
unsigned
size
=
prefix_size
+
num_digits
;
unsigned
size
=
prefix_size
+
num_digits
;
if
(
width
<=
size
)
{
if
(
width
<=
size
)
{
CharPtr
p
=
grow_buffer
(
size
);
CharPtr
p
=
grow_buffer
(
size
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
return
p
+
size
-
1
;
return
p
+
size
-
1
;
}
}
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
end
=
p
+
width
;
CharPtr
end
=
p
+
width
;
if
(
align
==
ALIGN_LEFT
)
{
if
(
align
==
ALIGN_LEFT
)
{
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
+=
size
;
p
+=
size
;
std
::
fill
(
p
,
end
,
fill
);
std
::
fill
(
p
,
end
,
fill
);
}
}
else
if
(
align
==
ALIGN_CENTER
)
{
else
if
(
align
==
ALIGN_CENTER
)
{
p
=
fill_padding
(
p
,
width
,
size
,
fill
);
p
=
fill_padding
(
p
,
width
,
size
,
fill
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
+=
size
;
p
+=
size
;
}
}
else
{
else
if
(
align
==
ALIGN_NUMERIC
)
{
{
if
(
prefix_size
!=
0
)
{
if
(
align
==
ALIGN_NUMERIC
)
{
if
(
prefix_size
!=
0
)
{
p
=
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
p
=
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
p
);
size
-=
prefix_size
;
size
-=
prefix_size
;
}
}
}
}
else
{
else
{
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
end
-
size
);
std
::
copy
(
prefix
,
prefix
+
prefix_size
,
end
-
size
);
}
}
std
::
fill
(
p
,
end
-
size
,
fill
);
std
::
fill
(
p
,
end
-
size
,
fill
);
...
@@ -2006,23 +2212,28 @@ BasicWriter<Char>::prepare_int_buffer(
...
@@ -2006,23 +2212,28 @@ BasicWriter<Char>::prepare_int_buffer(
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
T
,
typename
Spec
>
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
;
unsigned
prefix_size
=
0
;
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
UnsignedType
abs_value
=
value
;
UnsignedType
abs_value
=
value
;
char
prefix
[
4
]
=
""
;
char
prefix
[
4
]
=
""
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
prefix
[
0
]
=
'-'
;
prefix
[
0
]
=
'-'
;
++
prefix_size
;
++
prefix_size
;
abs_value
=
0
-
abs_value
;
abs_value
=
0
-
abs_value
;
}
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
prefix
[
0
]
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
prefix
[
0
]
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
++
prefix_size
;
++
prefix_size
;
}
}
switch
(
spec
.
type
())
{
switch
(
spec
.
type
())
{
case
0
:
case
0
:
case
'd'
:
{
case
'd'
:
{
unsigned
num_digits
=
internal
::
count_digits
(
abs_value
);
unsigned
num_digits
=
internal
::
count_digits
(
abs_value
);
CharPtr
p
=
prepare_int_buffer
(
CharPtr
p
=
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
)
+
1
-
num_digits
;
num_digits
,
spec
,
prefix
,
prefix_size
)
+
1
-
num_digits
;
...
@@ -2030,57 +2241,74 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
...
@@ -2030,57 +2241,74 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
break
;
break
;
}
}
case
'x'
:
case
'x'
:
case
'X'
:
{
case
'X'
:
{
UnsignedType
n
=
abs_value
;
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
spec
.
type
();
prefix
[
prefix_size
++
]
=
spec
.
type
();
}
}
unsigned
num_digits
=
0
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
++
num_digits
;
}
while
((
n
>>=
4
)
!=
0
);
}
while
((
n
>>=
4
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
n
=
abs_value
;
const
char
*
digits
=
spec
.
type
()
==
'x'
?
const
char
*
digits
=
spec
.
type
()
==
'x'
?
"0123456789abcdef"
:
"0123456789ABCDEF"
;
"0123456789abcdef"
:
"0123456789ABCDEF"
;
do
{
do
{
*
p
--
=
digits
[
n
&
0xf
];
*
p
--
=
digits
[
n
&
0xf
];
}
while
((
n
>>=
4
)
!=
0
);
}
while
((
n
>>=
4
)
!=
0
);
break
;
break
;
}
}
case
'b'
:
case
'b'
:
case
'B'
:
{
case
'B'
:
{
UnsignedType
n
=
abs_value
;
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
{
if
(
spec
.
flag
(
HASH_FLAG
))
{
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
spec
.
type
();
prefix
[
prefix_size
++
]
=
spec
.
type
();
}
}
unsigned
num_digits
=
0
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
++
num_digits
;
}
while
((
n
>>=
1
)
!=
0
);
}
while
((
n
>>=
1
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
n
=
abs_value
;
do
{
do
{
*
p
--
=
'0'
+
(
n
&
1
);
*
p
--
=
'0'
+
(
n
&
1
);
}
while
((
n
>>=
1
)
!=
0
);
}
while
((
n
>>=
1
)
!=
0
);
break
;
break
;
}
}
case
'o'
:
{
case
'o'
:
{
UnsignedType
n
=
abs_value
;
UnsignedType
n
=
abs_value
;
if
(
spec
.
flag
(
HASH_FLAG
))
if
(
spec
.
flag
(
HASH_FLAG
))
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
'0'
;
unsigned
num_digits
=
0
;
unsigned
num_digits
=
0
;
do
{
do
{
++
num_digits
;
++
num_digits
;
}
while
((
n
>>=
3
)
!=
0
);
}
while
((
n
>>=
3
)
!=
0
);
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
Char
*
p
=
get
(
prepare_int_buffer
(
num_digits
,
spec
,
prefix
,
prefix_size
));
n
=
abs_value
;
n
=
abs_value
;
do
{
do
{
*
p
--
=
'0'
+
(
n
&
7
);
*
p
--
=
'0'
+
(
n
&
7
);
}
while
((
n
>>=
3
)
!=
0
);
}
while
((
n
>>=
3
)
!=
0
);
break
;
break
;
}
}
default:
default:
...
@@ -2093,11 +2321,13 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
...
@@ -2093,11 +2321,13 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
template
<
typename
Char
>
template
<
typename
Char
>
template
<
typename
T
>
template
<
typename
T
>
void
BasicWriter
<
Char
>::
write_double
(
void
BasicWriter
<
Char
>::
write_double
(
T
value
,
const
FormatSpec
&
spec
)
{
T
value
,
const
FormatSpec
&
spec
)
{
// Check type.
// Check type.
char
type
=
spec
.
type
();
char
type
=
spec
.
type
();
bool
upper
=
false
;
bool
upper
=
false
;
switch
(
type
)
{
switch
(
type
)
{
case
0
:
case
0
:
type
=
'g'
;
type
=
'g'
;
break
;
break
;
...
@@ -2125,20 +2355,24 @@ void BasicWriter<Char>::write_double(
...
@@ -2125,20 +2355,24 @@ void BasicWriter<Char>::write_double(
char
sign
=
0
;
char
sign
=
0
;
// Use getsign instead of value < 0 because the latter is always
// Use getsign instead of value < 0 because the latter is always
// false for NaN.
// false for NaN.
if
(
internal
::
getsign
(
static_cast
<
double
>
(
value
)))
{
if
(
internal
::
getsign
(
static_cast
<
double
>
(
value
)))
{
sign
=
'-'
;
sign
=
'-'
;
value
=
-
value
;
value
=
-
value
;
}
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
}
}
if
(
value
!=
value
)
{
if
(
value
!=
value
)
{
// Format NaN ourselves because sprintf's output is not consistent
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
// across platforms.
std
::
size_t
nan_size
=
4
;
std
::
size_t
nan_size
=
4
;
const
char
*
nan
=
upper
?
" NAN"
:
" nan"
;
const
char
*
nan
=
upper
?
" NAN"
:
" nan"
;
if
(
!
sign
)
{
if
(
!
sign
)
{
--
nan_size
;
--
nan_size
;
++
nan
;
++
nan
;
}
}
...
@@ -2148,12 +2382,14 @@ void BasicWriter<Char>::write_double(
...
@@ -2148,12 +2382,14 @@ void BasicWriter<Char>::write_double(
return
;
return
;
}
}
if
(
internal
::
isinfinity
(
value
))
{
if
(
internal
::
isinfinity
(
value
))
{
// Format infinity ourselves because sprintf's output is not consistent
// Format infinity ourselves because sprintf's output is not consistent
// across platforms.
// across platforms.
std
::
size_t
inf_size
=
4
;
std
::
size_t
inf_size
=
4
;
const
char
*
inf
=
upper
?
" INF"
:
" inf"
;
const
char
*
inf
=
upper
?
" INF"
:
" inf"
;
if
(
!
sign
)
{
if
(
!
sign
)
{
--
inf_size
;
--
inf_size
;
++
inf
;
++
inf
;
}
}
...
@@ -2165,7 +2401,8 @@ void BasicWriter<Char>::write_double(
...
@@ -2165,7 +2401,8 @@ void BasicWriter<Char>::write_double(
std
::
size_t
offset
=
buffer_
.
size
();
std
::
size_t
offset
=
buffer_
.
size
();
unsigned
width
=
spec
.
width
();
unsigned
width
=
spec
.
width
();
if
(
sign
)
{
if
(
sign
)
{
buffer_
.
reserve
(
buffer_
.
size
()
+
(
std
::
max
)(
width
,
1u
));
buffer_
.
reserve
(
buffer_
.
size
()
+
(
std
::
max
)(
width
,
1u
));
if
(
width
>
0
)
if
(
width
>
0
)
--
width
;
--
width
;
...
@@ -2180,16 +2417,19 @@ void BasicWriter<Char>::write_double(
...
@@ -2180,16 +2417,19 @@ void BasicWriter<Char>::write_double(
unsigned
width_for_sprintf
=
width
;
unsigned
width_for_sprintf
=
width
;
if
(
spec
.
flag
(
HASH_FLAG
))
if
(
spec
.
flag
(
HASH_FLAG
))
*
format_ptr
++
=
'#'
;
*
format_ptr
++
=
'#'
;
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
if
(
spec
.
align
()
==
ALIGN_CENTER
)
{
width_for_sprintf
=
0
;
width_for_sprintf
=
0
;
}
}
else
{
else
{
if
(
spec
.
align
()
==
ALIGN_LEFT
)
if
(
spec
.
align
()
==
ALIGN_LEFT
)
*
format_ptr
++
=
'-'
;
*
format_ptr
++
=
'-'
;
if
(
width
!=
0
)
if
(
width
!=
0
)
*
format_ptr
++
=
'*'
;
*
format_ptr
++
=
'*'
;
}
}
if
(
spec
.
precision
()
>=
0
)
{
if
(
spec
.
precision
()
>=
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
*
format_ptr
++
=
'*'
;
}
}
...
@@ -2200,13 +2440,15 @@ void BasicWriter<Char>::write_double(
...
@@ -2200,13 +2440,15 @@ void BasicWriter<Char>::write_double(
// Format using snprintf.
// Format using snprintf.
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
Char
fill
=
static_cast
<
Char
>
(
spec
.
fill
());
for
(;;)
{
for
(;;)
{
std
::
size_t
buffer_size
=
buffer_
.
capacity
()
-
offset
;
std
::
size_t
buffer_size
=
buffer_
.
capacity
()
-
offset
;
#if _MSC_VER
#if _MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// 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.
// 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.
// 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_
.
reserve
(
offset
+
1
);
buffer_size
=
buffer_
.
capacity
()
-
offset
;
buffer_size
=
buffer_
.
capacity
()
-
offset
;
}
}
...
@@ -2214,27 +2456,33 @@ void BasicWriter<Char>::write_double(
...
@@ -2214,27 +2456,33 @@ void BasicWriter<Char>::write_double(
Char
*
start
=
&
buffer_
[
offset
];
Char
*
start
=
&
buffer_
[
offset
];
int
n
=
internal
::
CharTraits
<
Char
>::
format_float
(
int
n
=
internal
::
CharTraits
<
Char
>::
format_float
(
start
,
buffer_size
,
format
,
width_for_sprintf
,
spec
.
precision
(),
value
);
start
,
buffer_size
,
format
,
width_for_sprintf
,
spec
.
precision
(),
value
);
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
capacity
())
{
if
(
n
>=
0
&&
offset
+
n
<
buffer_
.
capacity
())
if
(
sign
)
{
{
if
(
sign
)
{
if
((
spec
.
align
()
!=
ALIGN_RIGHT
&&
spec
.
align
()
!=
ALIGN_DEFAULT
)
||
if
((
spec
.
align
()
!=
ALIGN_RIGHT
&&
spec
.
align
()
!=
ALIGN_DEFAULT
)
||
*
start
!=
' '
)
{
*
start
!=
' '
)
{
*
(
start
-
1
)
=
sign
;
*
(
start
-
1
)
=
sign
;
sign
=
0
;
sign
=
0
;
}
}
else
{
else
{
*
(
start
-
1
)
=
fill
;
*
(
start
-
1
)
=
fill
;
}
}
++
n
;
++
n
;
}
}
if
(
spec
.
align
()
==
ALIGN_CENTER
&&
if
(
spec
.
align
()
==
ALIGN_CENTER
&&
spec
.
width
()
>
static_cast
<
unsigned
>
(
n
))
{
spec
.
width
()
>
static_cast
<
unsigned
>
(
n
))
{
width
=
spec
.
width
();
width
=
spec
.
width
();
CharPtr
p
=
grow_buffer
(
width
);
CharPtr
p
=
grow_buffer
(
width
);
std
::
copy
(
p
,
p
+
n
,
p
+
(
width
-
n
)
/
2
);
std
::
copy
(
p
,
p
+
n
,
p
+
(
width
-
n
)
/
2
);
fill_padding
(
p
,
spec
.
width
(),
n
,
fill
);
fill_padding
(
p
,
spec
.
width
(),
n
,
fill
);
return
;
return
;
}
}
if
(
spec
.
fill
()
!=
' '
||
sign
)
{
if
(
spec
.
fill
()
!=
' '
||
sign
)
{
while
(
*
start
==
' '
)
while
(
*
start
==
' '
)
*
start
++
=
fill
;
*
start
++
=
fill
;
if
(
sign
)
if
(
sign
)
...
@@ -2284,7 +2532,8 @@ accessed as a C string with ``out.c_str()``.
...
@@ -2284,7 +2532,8 @@ accessed as a C string with ``out.c_str()``.
\endrst
\endrst
*/
*/
template
<
typename
Char
,
typename
Allocator
=
std
::
allocator
<
Char
>
>
template
<
typename
Char
,
typename
Allocator
=
std
::
allocator
<
Char
>
>
class
BasicMemoryWriter
:
public
BasicWriter
<
Char
>
{
class
BasicMemoryWriter
:
public
BasicWriter
<
Char
>
{
private:
private:
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
,
Allocator
>
buffer_
;
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
,
Allocator
>
buffer_
;
...
@@ -2298,13 +2547,15 @@ public:
...
@@ -2298,13 +2547,15 @@ public:
of the other object to it.
of the other object to it.
*/
*/
BasicMemoryWriter
(
BasicMemoryWriter
&&
other
)
BasicMemoryWriter
(
BasicMemoryWriter
&&
other
)
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
std
::
move
(
other
.
buffer_
))
{
:
BasicWriter
<
Char
>
(
buffer_
),
buffer_
(
std
::
move
(
other
.
buffer_
))
{
}
}
/**
/**
Moves the content of the other ``BasicMemoryWriter`` object to this one.
Moves the content of the other ``BasicMemoryWriter`` object to this one.
*/
*/
BasicMemoryWriter
&
operator
=
(
BasicMemoryWriter
&&
other
)
{
BasicMemoryWriter
&
operator
=
(
BasicMemoryWriter
&&
other
)
{
buffer_
=
std
::
move
(
other
.
buffer_
);
buffer_
=
std
::
move
(
other
.
buffer_
);
return
*
this
;
return
*
this
;
}
}
...
@@ -2316,7 +2567,8 @@ typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
...
@@ -2316,7 +2567,8 @@ typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
// Formats a value.
// Formats a value.
template
<
typename
Char
,
typename
T
>
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
;
std
::
basic_ostringstream
<
Char
>
os
;
os
<<
value
;
os
<<
value
;
internal
::
Arg
arg
;
internal
::
Arg
arg
;
...
@@ -2335,7 +2587,8 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
...
@@ -2335,7 +2587,8 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32
#ifdef _WIN32
/** A Windows error. */
/** A Windows error. */
class
WindowsError
:
public
SystemError
{
class
WindowsError
:
public
SystemError
{
private:
private:
void
init
(
int
error_code
,
StringRef
format_str
,
ArgList
args
);
void
init
(
int
error_code
,
StringRef
format_str
,
ArgList
args
);
...
@@ -2368,7 +2621,8 @@ public:
...
@@ -2368,7 +2621,8 @@ public:
}
}
\endrst
\endrst
*/
*/
WindowsError
(
int
error_code
,
StringRef
message
)
{
WindowsError
(
int
error_code
,
StringRef
message
)
{
init
(
error_code
,
message
,
ArgList
());
init
(
error_code
,
message
,
ArgList
());
}
}
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
StringRef
)
FMT_VARIADIC_CTOR
(
WindowsError
,
init
,
int
,
StringRef
)
...
@@ -2399,13 +2653,15 @@ Formats arguments and returns the result as a string.
...
@@ -2399,13 +2653,15 @@ Formats arguments and returns the result as a string.
std::string message = format("The answer is {}", 42);
std::string message = format("The answer is {}", 42);
\endrst
\endrst
*/
*/
inline
std
::
string
format
(
StringRef
format_str
,
ArgList
args
)
{
inline
std
::
string
format
(
StringRef
format_str
,
ArgList
args
)
{
MemoryWriter
w
;
MemoryWriter
w
;
w
.
write
(
format_str
,
args
);
w
.
write
(
format_str
,
args
);
return
w
.
str
();
return
w
.
str
();
}
}
inline
std
::
wstring
format
(
WStringRef
format_str
,
ArgList
args
)
{
inline
std
::
wstring
format
(
WStringRef
format_str
,
ArgList
args
)
{
WMemoryWriter
w
;
WMemoryWriter
w
;
w
.
write
(
format_str
,
args
);
w
.
write
(
format_str
,
args
);
return
w
.
str
();
return
w
.
str
();
...
@@ -2445,7 +2701,8 @@ print(cerr, "Don't {}!", "panic");
...
@@ -2445,7 +2701,8 @@ print(cerr, "Don't {}!", "panic");
void
print
(
std
::
ostream
&
os
,
StringRef
format_str
,
ArgList
args
);
void
print
(
std
::
ostream
&
os
,
StringRef
format_str
,
ArgList
args
);
template
<
typename
Char
>
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
);
internal
::
PrintfFormatter
<
Char
>
().
format
(
w
,
format
,
args
);
}
}
...
@@ -2458,7 +2715,8 @@ Formats arguments and returns the result as a string.
...
@@ -2458,7 +2715,8 @@ Formats arguments and returns the result as a string.
std::string message = fmt::sprintf("The answer is %d", 42);
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
\endrst
*/
*/
inline
std
::
string
sprintf
(
StringRef
format
,
ArgList
args
)
{
inline
std
::
string
sprintf
(
StringRef
format
,
ArgList
args
)
{
MemoryWriter
w
;
MemoryWriter
w
;
printf
(
w
,
format
,
args
);
printf
(
w
,
format
,
args
);
return
w
.
str
();
return
w
.
str
();
...
@@ -2484,14 +2742,16 @@ Prints formatted data to ``stdout``.
...
@@ -2484,14 +2742,16 @@ Prints formatted data to ``stdout``.
fmt::printf("Elapsed time: %.2f seconds", 1.23);
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
\endrst
*/
*/
inline
int
printf
(
StringRef
format
,
ArgList
args
)
{
inline
int
printf
(
StringRef
format
,
ArgList
args
)
{
return
fprintf
(
stdout
,
format
,
args
);
return
fprintf
(
stdout
,
format
,
args
);
}
}
/**
/**
Fast integer formatter.
Fast integer formatter.
*/
*/
class
FormatInt
{
class
FormatInt
{
private:
private:
// Buffer should be large enough to hold all digits (digits10 + 1),
// Buffer should be large enough to hold all digits (digits10 + 1),
// a sign and a null character.
// a sign and a null character.
...
@@ -2500,9 +2760,11 @@ private:
...
@@ -2500,9 +2760,11 @@ private:
char
*
str_
;
char
*
str_
;
// Formats value in reverse and returns the number of digits.
// 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
;
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
// 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
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
// "Three Optimization Tips for C++". See speed-test for a comparison.
...
@@ -2511,7 +2773,8 @@ private:
...
@@ -2511,7 +2773,8 @@ private:
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
+
1
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
+
1
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
];
*--
buffer_end
=
internal
::
Data
::
DIGITS
[
index
];
}
}
if
(
value
<
10
)
{
if
(
value
<
10
)
{
*--
buffer_end
=
static_cast
<
char
>
(
'0'
+
value
);
*--
buffer_end
=
static_cast
<
char
>
(
'0'
+
value
);
return
buffer_end
;
return
buffer_end
;
}
}
...
@@ -2521,7 +2784,8 @@ private:
...
@@ -2521,7 +2784,8 @@ private:
return
buffer_end
;
return
buffer_end
;
}
}
void
FormatSigned
(
LongLong
value
)
{
void
FormatSigned
(
LongLong
value
)
{
ULongLong
abs_value
=
static_cast
<
ULongLong
>
(
value
);
ULongLong
abs_value
=
static_cast
<
ULongLong
>
(
value
);
bool
negative
=
value
<
0
;
bool
negative
=
value
<
0
;
if
(
negative
)
if
(
negative
)
...
@@ -2532,13 +2796,16 @@ private:
...
@@ -2532,13 +2796,16 @@ private:
}
}
public:
public:
explicit
FormatInt
(
int
value
)
{
explicit
FormatInt
(
int
value
)
{
FormatSigned
(
value
);
FormatSigned
(
value
);
}
}
explicit
FormatInt
(
long
value
)
{
explicit
FormatInt
(
long
value
)
{
FormatSigned
(
value
);
FormatSigned
(
value
);
}
}
explicit
FormatInt
(
LongLong
value
)
{
explicit
FormatInt
(
LongLong
value
)
{
FormatSigned
(
value
);
FormatSigned
(
value
);
}
}
explicit
FormatInt
(
unsigned
value
)
:
str_
(
format_decimal
(
value
))
{}
explicit
FormatInt
(
unsigned
value
)
:
str_
(
format_decimal
(
value
))
{}
...
@@ -2548,7 +2815,8 @@ public:
...
@@ -2548,7 +2815,8 @@ public:
/**
/**
Returns the number of characters written to the output buffer.
Returns the number of characters written to the output buffer.
*/
*/
std
::
size_t
size
()
const
{
std
::
size_t
size
()
const
{
return
buffer_
-
str_
+
BUFFER_SIZE
-
1
;
return
buffer_
-
str_
+
BUFFER_SIZE
-
1
;
}
}
...
@@ -2556,7 +2824,8 @@ public:
...
@@ -2556,7 +2824,8 @@ public:
Returns a pointer to the output buffer content. No terminating null
Returns a pointer to the output buffer content. No terminating null
character is appended.
character is appended.
*/
*/
const
char
*
data
()
const
{
const
char
*
data
()
const
{
return
str_
;
return
str_
;
}
}
...
@@ -2564,7 +2833,8 @@ public:
...
@@ -2564,7 +2833,8 @@ public:
Returns a pointer to the output buffer content with terminating null
Returns a pointer to the output buffer content with terminating null
character appended.
character appended.
*/
*/
const
char
*
c_str
()
const
{
const
char
*
c_str
()
const
{
buffer_
[
BUFFER_SIZE
-
1
]
=
'\0'
;
buffer_
[
BUFFER_SIZE
-
1
]
=
'\0'
;
return
str_
;
return
str_
;
}
}
...
@@ -2572,7 +2842,8 @@ public:
...
@@ -2572,7 +2842,8 @@ public:
/**
/**
Returns the content of the output buffer as an `std::string`.
Returns the content of the output buffer as an `std::string`.
*/
*/
std
::
string
str
()
const
{
std
::
string
str
()
const
{
return
std
::
string
(
str_
,
size
());
return
std
::
string
(
str_
,
size
());
}
}
};
};
...
@@ -2581,14 +2852,18 @@ public:
...
@@ -2581,14 +2852,18 @@ public:
// a pointer to the end of the formatted string. This function doesn't
// a pointer to the end of the formatted string. This function doesn't
// write a terminating null character.
// write a terminating null character.
template
<
typename
T
>
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
;
typename
internal
::
IntTraits
<
T
>::
MainType
abs_value
=
value
;
if
(
internal
::
is_negative
(
value
))
{
if
(
internal
::
is_negative
(
value
))
{
*
buffer
++
=
'-'
;
*
buffer
++
=
'-'
;
abs_value
=
0
-
abs_value
;
abs_value
=
0
-
abs_value
;
}
}
if
(
abs_value
<
100
)
{
if
(
abs_value
<
100
)
if
(
abs_value
<
10
)
{
{
if
(
abs_value
<
10
)
{
*
buffer
++
=
static_cast
<
char
>
(
'0'
+
abs_value
);
*
buffer
++
=
static_cast
<
char
>
(
'0'
+
abs_value
);
return
;
return
;
}
}
...
@@ -2708,7 +2983,8 @@ fmt::print(format, args...);
...
@@ -2708,7 +2983,8 @@ fmt::print(format, args...);
#define FMT_VARIADIC_W(ReturnType, func, ...) \
#define FMT_VARIADIC_W(ReturnType, func, ...) \
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__)
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__)
namespace
fmt
{
namespace
fmt
{
FMT_VARIADIC
(
std
::
string
,
format
,
StringRef
)
FMT_VARIADIC
(
std
::
string
,
format
,
StringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
WStringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
format
,
WStringRef
)
FMT_VARIADIC
(
void
,
print
,
StringRef
)
FMT_VARIADIC
(
void
,
print
,
StringRef
)
...
...
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